home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 February / EnigmA AMIGA RUN 15 (1997)(G.R. Edizioni)(IT)[!][issue 1997-02][PLANET CD V].iso / enigma / earcd / sviluppo / svilupp2 / amphn192.lha / src / amiphoned.c < prev    next >
C/C++ Source or Header  |  1996-11-16  |  66KB  |  2,367 lines

  1. #define DICE_C
  2.  
  3. #include <stdio.h>
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include <time.h>
  7.  
  8. #include <exec/types.h>
  9. #include <exec/io.h>
  10. #include <exec/lists.h>
  11. #include <exec/memory.h>
  12. #include <devices/audio.h>
  13. #include <libraries/dos.h>            /* contains RETURN_OK, RETURN_WARN #def's */
  14. #include <dos/dos.h>
  15. #include <dos/dosextens.h>
  16. #include <dos/dostags.h>
  17. #include <dos/var.h>
  18. #include <dos/exall.h>
  19. #include <graphics/gfxbase.h>        /* to determine if we are on a PAL or NTSC Amiga */
  20. #include <intuition/intuition.h>
  21. #include <libraries/gadtools.h>
  22.  
  23. #include <clib/exec_protos.h>
  24. #include <clib/alib_protos.h>
  25. #include <clib/dos_protos.h>
  26. #include <clib/intuition_protos.h>
  27. #include <clib/icon_protos.h>
  28. #include <clib/gadtools_protos.h>
  29. #include <clib/graphics_protos.h>
  30.  
  31. #include <errno.h>
  32. #include <inetd.h>
  33. #include <sys/types.h>
  34.  
  35. #include <proto/socket.h>
  36. #include <sys/errno.h>
  37. #include <sys/types.h>
  38. #include <sys/socket.h>
  39. #include <sys/ioctl.h>
  40. #include <sys/syslog.h>
  41. #include <netdb.h>
  42.  
  43. #include <pragmas/socket_pragmas.h>
  44. #include <inetd.h>
  45.  
  46. #include "AmiPhoned.h"
  47. #include "AmiPhoneMsg.h"
  48. #include "AmiPhonePacket.h"
  49. #include "codec.h"
  50. #include "StringRequest.h"
  51. #include "TCPQueue.h"
  52.  
  53. #define MIN_CHIP_MEMORY     50000
  54. #define CLIENT_TCP_QUEUE 10
  55.  
  56. #define OPTION_DENY        0
  57. #define OPTION_TWOWAY        1
  58. #define OPTION_LISTEN        2
  59. #define OPTION_TAKEMESSAGE    3
  60.  
  61. #define P_LAUNCH    100
  62. #define P_INCREMENT    101
  63. #define P_DECREMENT    102
  64. #define P_RECORD    103
  65. #define P_FLUSHBUFFER   104
  66. #define P_HIDEWINDOW    105
  67. #define P_ABOUT     106
  68. #define P_QUIT        107
  69.  
  70. #define R_ADDRELAY    200
  71. #define R_RELAY        250
  72.  
  73. #define EXTRA_WINDOW_WIDTH 65
  74.  
  75. #ifdef DEBUG_FLAG
  76. FILE * fpDebug = NULL;
  77. #define DEBUG(X)  {fprintf(fpDebug,X); fflush(fpDebug);}
  78. #endif
  79.  
  80. #ifndef DEBUG_FLAG
  81. #define DEBUG(X)  {};
  82. #endif
  83.  
  84. /* Why does this come out as 18 unless I define it explicitely here?  Weird! */
  85. #define EWOULDBLOCK 35
  86.  
  87. /* private functions */
  88. static int UserReceiveOption(BOOL BCanTakeMessage, char * szMessage);
  89.  
  90. /* vars shared with codec.c */
  91. char * szMessageDir = NULL;
  92. ULONG ulByteTicker, ulMilliSecondsTaken = 0L;
  93.  
  94. /* Offset to first relay-add entry--MUST BE CHANGED WHENEVER MeNU ITEMS ARE ADDED! */
  95. #define ADD_RELAY_BASE 9
  96.  
  97. /* menus */
  98. struct NewMenu nmMenus[] = {
  99.     NM_TITLE, "Project",         NULL,  0L,         NULL, NULL,
  100.     NM_ITEM,  "Start Client",     "S",  0L,        NULL, (void *) P_LAUNCH,
  101.     NM_ITEM,  "Startup Delay",   NULL,  0L,        NULL, NULL,
  102.     NM_SUB,   "Increase",          "]",  0L,        NULL, (void *) P_INCREMENT,
  103.     NM_SUB,   "Decrease",          "[",  0L,        NULL, (void *) P_DECREMENT,
  104.     NM_ITEM,  "Record",            "R",  CHECKIT,    NULL, (void *) P_RECORD,
  105.     NM_ITEM,  "Flush Buffer",     "F",  0L,         NULL, (void *) P_FLUSHBUFFER,
  106.     NM_ITEM,  "Hide",             "H",  0L,         NULL, (void *) P_HIDEWINDOW,
  107.     NM_ITEM,  "About",            "?",  0L,         NULL, (void *) P_ABOUT,
  108.     NM_ITEM,  NM_BARLABEL,       NULL,  0L,         NULL, NULL,
  109.     NM_ITEM,  "Quit",             "Q",  0L,         NULL, (void *) P_QUIT,
  110.     NM_TITLE, "Relay",           NULL,  0L,        NULL, NULL,
  111.     NM_ITEM,  "--------------",   "1",  0L,     NULL, (void *) (R_ADDRELAY),
  112.     NM_ITEM,  "--------------",   "2",  0L,     NULL, (void *) (R_ADDRELAY+1),
  113.     NM_ITEM,  "--------------",   "3",  0L,     NULL, (void *) (R_ADDRELAY+2),
  114.     NM_ITEM,  "--------------",   "4",  0L,     NULL, (void *) (R_ADDRELAY+3),
  115.     NM_ITEM,  "--------------",   "5",  0L,     NULL, (void *) (R_ADDRELAY+4),
  116.     NM_ITEM,  "--------------",   "6",  0L,     NULL, (void *) (R_ADDRELAY+5),
  117.     NM_ITEM,  "--------------",   "7",  0L,     NULL, (void *) (R_ADDRELAY+6),
  118.     NM_ITEM,  "--------------",   "8",  0L,     NULL, (void *) (R_ADDRELAY+7),
  119.     NM_ITEM,  "--------------",   "9",  0L,     NULL, (void *) (R_ADDRELAY+8),
  120.     NM_ITEM,  "--------------",   "0",  0L,     NULL, (void *) (R_ADDRELAY+9),
  121.     NM_END,   NULL,             NULL,  NULL,       NULL, NULL
  122. };
  123.  
  124. #define MAXRELAYNAMELEN 14
  125.  
  126. #define QMODE_EMPTY 0    /* Queue is filling--don't play packets yet */
  127. #define QMODE_FLUSH 1    /* Queue is flushing--play packets until empty */
  128.  
  129. /* private vars for this module */
  130. static char [] = VERSION_STRING;
  131. static char * szRelayName[10] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
  132. static LONG   sRelayUDPSocket[10]= {-1  ,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1};
  133. struct sockaddr_in saRelayTCPAddress[10];
  134. struct sockaddr_in saRelayUDPAddress[10];
  135.  
  136. static USHORT port;
  137. LONG   sRelayTCPSocket[10]= {-1  ,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1};
  138. static LONG   sTCPSocket=-1,sUDPSocket=-1;
  139. static UBYTE  *uQ=NULL;
  140. static BOOL   BNoReq = FALSE, BLocalAmiPhoneNotified = FALSE, BNetConnect = FALSE, BRecordMessage = FALSE, BImARelay = FALSE, BSendWarningBack = FALSE;
  141. static struct AmiPhoneInfo MyInfo;        /* shared mem for communicating with local AmiPhone */
  142. static struct AmiPhoneSendBuffer recBuffer;    /* buffer to receive incoming data from remote AmiPhone */
  143.  
  144. static char szExitMessage[100] = "All Done";
  145. static int  ngExitVal = RETURN_OK;
  146. static int  nWindowWidth=0;
  147.  
  148. static int nRelayToAdd = 0, nQMode = QMODE_EMPTY;
  149. static int nQLength = 0, nQLengthMS = 0, nPri = 0, nMaxVoiceMailDirSize = 2048, nMaxMessageSize = -1;
  150. static char * szProgPath;
  151. static LONG lPlayUpTo = -1L;
  152. static ULONG ulLowIndex = 0L;        /* packets numbered lower than this var will not be added, or played */
  153. static ULONG ulPhonedMask, ulSignalMessageFree = 0L;
  154. static BDone = FALSE, BOpenWindow = FALSE, BAudioAvail=FALSE;
  155. static BOOL BNoClient = TRUE;
  156. static ULONG ulKeyCode = 0L;
  157. static char szShortPeerName[20]="";
  158. static char szAwayVar[35] = "";        /* name of ENV var to look for to decide if user is away or not */
  159. static FILE * fpOut = NULL;        /* save output to... */
  160.  
  161. static struct sockaddr_in saTCPSocket;    /* this is the socket we send/receive commands over */
  162. static struct sockaddr_in saUDPSocket;    /* this is the socket we set up and receive data on */
  163. static struct List * PacketList;
  164. static struct Window * AmiPhonedWindow = NULL;
  165. static struct Screen * AmiPhonedScreen = NULL;
  166. static struct Menu * Menu = NULL;
  167.  
  168. static char targethost[100]="";
  169.  
  170. static time_t tTimeConnected;
  171.  
  172. /* user prefs */
  173. int windowtop = -1, windowleft = -1;    /* default: top, centered. */
  174.  
  175. /* global variables for audio output */
  176. struct IOAudio    *AIOptr1=NULL, *AIOptr2=NULL;
  177. struct MsgPort    *port1=NULL, *port2=NULL;
  178.  
  179. /* The number of milliseconds of audio that must be in the queue before 
  180.    AmiPhoned will start playing them.  Raise this to prevent skipping, 
  181.    lower it to reduce the sample-til-play delay */
  182. int nMinReserve = 800;
  183.  
  184. struct GfxBase    *GfxBase = NULL;
  185.  
  186. BYTE     bStatus[2] = {STATUS_INVALID, STATUS_INVALID};        /* status of each audio buffer */
  187. #define AUDIO_EMPTY    ((bStatus[0]==STATUS_INVALID)&&(bStatus[1]==STATUS_INVALID))
  188. #define AUDIO_HALF    (bStatus[0]!=bStatus[1])
  189. #define AUDIO_FULL    ((bStatus[0]==STATUS_PLAYING)&&(bStatus[1]==STATUS_PLAYING))
  190.  
  191. /* These WERE main()'s locals in AUDIO */
  192. ULONG  SystemClock;    /* PAL/NTSC clock constant */
  193. ULONG  length[2];    /* sample lengths */
  194. ULONG  speed;        /* playback rate */
  195. BYTE   *psample[2];    /* pointers to samples */
  196.  
  197. /* global vars */
  198. struct Library * IntuitionBase = NULL;
  199. struct Library * SocketBase    = NULL;
  200. struct Library * IconBase      = NULL;
  201. struct Library * GadToolsBase  = NULL;
  202.  
  203. const static BOOL Not[2] = {TRUE,FALSE};
  204.  
  205.  
  206.  
  207. BOOL SetAsyncMode(BOOL BAsynch, int sCurrSocket)
  208. {
  209.     LONG lNonBlockCode = BAsynch;
  210.         
  211.     if (IoctlSocket(sCurrSocket, FIONBIO, (char *)&lNonBlockCode) < 0) return(FALSE); 
  212.     return(TRUE);
  213. }
  214.  
  215.  
  216.  
  217.  
  218.  
  219. /* Tries to copy the name of whoever is at the other end of our
  220.    TCP socket into sBuffer, whose length is nBufLen.  */
  221. void GetPhonePeerName(char *sBuffer, int nBufLen)
  222. {
  223.     LONG lLength = sizeof(struct sockaddr_in);
  224.     struct hostent *hePeer = NULL;
  225.     struct sockaddr_in saTempAdd;
  226.     
  227.         UNLESS(SocketBase) 
  228.         {
  229.         *sBuffer = '\0';    /* Can't do much w/o AmiTCP running */
  230.         return;
  231.     }
  232.     
  233.     if (getpeername(sTCPSocket, &saTempAdd, &lLength) < 0) 
  234.     {
  235.         sprintf(sBuffer,"gpn err %i",errno);
  236.         DMakeReq(NULL,sBuffer,NULL);
  237.     }    
  238.     else hePeer = gethostbyaddr((caddr_t)&saTempAdd.sin_addr, sizeof(saTempAdd.sin_addr), AF_INET);
  239.     
  240.     Strncpy(sBuffer, hePeer? hePeer->h_name : "(unknown)", nBufLen);
  241.     return;
  242. }    
  243.     
  244.  
  245.  
  246. /* This function does the accepting of the socket from inetd. */    
  247. BOOL AcceptTCPSocket(struct DaemonMessage *dm)
  248. {
  249.     LONG ulTrue = TRUE;    /* gotta pass it by reference, la la */
  250.      LONG ulAddrSize = sizeof(struct sockaddr_in);
  251.          
  252.     /* This function is called when we were started by inetd.  It hooks
  253.        us up with the calling program! */
  254.     if ((dm == NULL)||(SocketBase == NULL)) return(FALSE);
  255.  
  256.     sTCPSocket = ObtainSocket((LONG)dm->dm_Id,(LONG) dm->dm_Family,(LONG) dm->dm_Type, 0L);
  257.     if (sTCPSocket < 0) EXIT("ObtainSocket() failed.",RETURN_ERROR);
  258.     
  259.     /* Get the user init data and address */
  260.     PhonedWait(0L);        /* Wait for connect packet */
  261.     
  262.     UNLESS(BNetConnect) EXIT("Couldn't get connection info!\n(Are you and the caller using\nthe latest version of AmiPhone?)",RETURN_ERROR)
  263.  
  264.     if (SafePutToPort(NULL,AmiPhonePortName()))
  265.     {
  266.         BNoReq = TRUE;
  267.         #ifdef DEBUG_FLAG
  268.         fprintf(fpDebug,"Port found: [%s]\n",AmiPhonePortName()); fflush(fpDebug);
  269.         #endif
  270.     }
  271.     else 
  272.     {
  273.         #ifdef DEBUG_FLAG
  274.         fprintf(fpDebug,"Port not found: [%s]\n",AmiPhonePortName()); fflush(fpDebug);
  275.         #endif
  276.     }
  277.     return(TRUE);     
  278. }
  279.  
  280.  
  281. /* Closes sTCPSocket and sUDPSocket, and if BSendDisconnect is TRUE, it will
  282.    tell the remote socket about it with a PHONECOMMAND_DISCONNECT packet */
  283. BOOL ClosePhonedConnection(BOOL BSendDisconnect)
  284. {
  285.     struct sockaddr_in saNullAddress;
  286.     
  287.         if (SocketBase == NULL) return(FALSE);
  288.  
  289.     /* Tell our peer we're outta here, if he didn't disconnect first */
  290.     if (BSendDisconnect == TRUE) 
  291.     {
  292.         #ifdef DEBUG_FLAG
  293.             DEBUG("Sending disconnect packet...\n")
  294.         #endif
  295.         
  296.         SendCommandPacket(PHONECOMMAND_DISCONNECT, 0, 0L);
  297.     }
  298.     if (sUDPSocket >= 0)
  299.     {
  300.         saNullAddress.sin_family = AF_UNSPEC;    /* to cause a disconnect */
  301.         connect(sUDPSocket, &saNullAddress, sizeof(saNullAddress));
  302.         CloseSocket(sUDPSocket);
  303.         sUDPSocket = -1;
  304.     }
  305.     if (sTCPSocket >= 0)
  306.     {
  307.         CloseSocket(sTCPSocket);
  308.         sTCPSocket = -1;
  309.     }
  310.     BNetConnect = FALSE;
  311.     return(TRUE);
  312. }
  313.  
  314.  
  315.  
  316.  
  317. /* Creates and sets up a the UDP socket that we will be receiving
  318.    data packets over.  */
  319. LONG CreateUDPSocket(void)
  320. {
  321.     LONG sNewSocket;
  322.     BOOL BDone = FALSE;
  323.     int nPortNum;
  324.     
  325.     if ((sNewSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
  326.     {
  327.         DMakeReq(NULL,"Couldn't create UDP socket",NULL);
  328.         return(sNewSocket);
  329.     }
  330.     
  331.     /* a new socket... */        
  332.         bzero(&saUDPSocket, sizeof(saUDPSocket));
  333.  
  334.     /* set it up... */            
  335.     saUDPSocket.sin_family = AF_INET;
  336.     saUDPSocket.sin_addr.s_addr = htonl(INADDR_ANY);
  337.     
  338.         /* associate it with the socket we just made */ 
  339.     for (nPortNum = IPPORT_USERRESERVED+1; nPortNum < (IPPORT_USERRESERVED+200); nPortNum++)
  340.     {
  341.           saUDPSocket.sin_port = htons(nPortNum);
  342.         if (bind(sNewSocket, (struct sockaddr *) &saUDPSocket, sizeof(saUDPSocket)) == 0)
  343.         {
  344.             SetAsyncMode(TRUE, sNewSocket);
  345.             return(sNewSocket);
  346.         }
  347.         #ifdef DEBUG_FLAG
  348.             fprintf(fpDebug,"port %i: bind failed, errno=%i\n",nPortNum,errno);
  349.             fflush(fpDebug);
  350.         #endif
  351.     }
  352.  
  353.     #ifdef DEBUG_FLAG
  354.         fprintf(fpDebug,"CreateUDPSocket failed, errno = %i\n",errno);
  355.         fflush(fpDebug);
  356.     #endif
  357.     
  358.     return(-1);    /* failure */
  359. }
  360.  
  361.  
  362. /* Creates the UDP data reception socket, and sends a command to tell 
  363.    the client where it is. */
  364. BOOL CreateUDPConnection(UBYTE ubReplyType)
  365. {
  366.     /* Create and bind our new socket to a local port */
  367.     sUDPSocket = CreateUDPSocket();
  368.  
  369.     if (sUDPSocket == -1) return(FALSE);
  370.         
  371.     /* This should fill out the local half of the deal */
  372.     if (SendCommandPacket(PHONECOMMAND_REPLY, ubReplyType, saUDPSocket.sin_port) == FALSE)
  373.     {
  374.         #ifdef DEBUG_FLAG
  375.             fprintf(fpDebug,"CreateUDPConnection: send REPLY failed, errno = %i\n",errno);
  376.             fflush(fpDebug);
  377.         #endif
  378.         return(FALSE);
  379.     }
  380.     
  381.     /* If we can't take a message, no point in continuing... */
  382.     if (ubReplyType == PCREPLY_CANTLEAVEMESSAGE) EXIT("Couldn't accept incoming voice mail",RETURN_OK)
  383.     if (ubReplyType == PCREPLY_LEAVEMESSAGE) BRecordMessage = TRUE;    
  384.  
  385.     return(TRUE);
  386. }
  387.  
  388.  
  389. /* This function sends a command/header packet back to the AmiPhone client.  */
  390. BOOL SendCommandPacket(UBYTE ubCommand, UBYTE ubType, ULONG ulData)
  391. {
  392.     struct AmiPhonePacketHeader sendme;
  393.  
  394.     UNLESS((BNetConnect)&&(SocketBase)) return(FALSE);
  395.  
  396.     /* initialize our packet structure */
  397.     sendme.ubCommand = ubCommand;
  398.     sendme.ubType    = ubType;
  399.     sendme.ulBPS     = ulData;
  400.     sendme.ulDataLen = 0L;            /* we only send this header */
  401.  
  402.     /* a nasty hack--I want to send the number of kbytes available for
  403.        a message, so I'm putting it in ulJoinCode. */
  404.     if (ulSignalMessageFree > 0L) 
  405.     {
  406.         sendme.ulJoinCode= ulSignalMessageFree;
  407.         ulSignalMessageFree = 0;
  408.     }
  409.     
  410.     AttemptTCPSend(sTCPSocket, CLIENT_TCP_QUEUE, (UBYTE *)&sendme, sizeof(sendme));
  411.     return(TRUE);
  412. }
  413.  
  414.  
  415. int DMakeReq(char *sTitle, char *sText, char *sGadgets)
  416. {
  417.     struct EasyStruct myreq;
  418.     LONG number = 0L;
  419.     int nResult;
  420.  
  421.     if (sTitle == NULL) sTitle = "AmiPhoned Message";
  422.     if (sText == NULL) sText = "Hey, something's up!";
  423.     if (sGadgets == NULL) sGadgets = "OK";
  424.  
  425.     myreq.es_TextFormat   = sText;
  426.     myreq.es_Title        = sTitle;
  427.     myreq.es_GadgetFormat = sGadgets;
  428.  
  429.     nResult = EasyRequest(NULL, &myreq, NULL, NULL, number);
  430.     return(nResult);
  431. }
  432.  
  433. void SetExitMessage(char * message, int nExitVal)
  434. {
  435.     Strncpy(szExitMessage,message,sizeof(szExitMessage));
  436.     ngExitVal = nExitVal;
  437. }
  438.  
  439.  
  440. void FinalizeOutFile(void)
  441. {
  442.     ULONG ulSecondsTaken = ulMilliSecondsTaken / 1000;
  443.     
  444.     if (fpOut)
  445.     {    
  446.         fclose(fpOut);
  447.         /* set a file note if we can */
  448.         SetMessageNote(tTimeConnected, targethost, szMessageDir, ulSecondsTaken ? ulSecondsTaken : 1L);
  449.         fpOut = NULL;    
  450.     }
  451. }
  452.  
  453. void CleanExit(void)
  454. {
  455.     ULONG ulLength=sizeof(struct sockaddr_in);
  456.     char szBuf[25];
  457.     int i;
  458.         
  459.     FinalizeOutFile();
  460.     
  461.     if (szMessageDir) FreeMem(szMessageDir,strlen(szMessageDir));
  462.     
  463.     if (AmiPhonedWindow) CloseTitleBar(&ulPhonedMask);
  464.     if (AmiPhonedScreen) UnlockPubScreen(NULL, AmiPhonedScreen);
  465.  
  466.     /* Close the relays */
  467.     for (i=0;i<10;i++) RemoveRelay(i,TRUE);
  468.     
  469.     #ifdef DEBUG_FLAG
  470.         fprintf(fpDebug,"Closing sockets, %s\n", BNetConnect ? "with sending packet" : "no packet will be sent");
  471.         fflush(fpDebug);
  472.     #endif
  473.         
  474.     /* close connect socket if it's open */
  475.     ClosePhonedConnection(BNetConnect);
  476.  
  477.     /* Give the PHONECOMMAND_DISCONNECT time to be received before we
  478.        tell the local client we're done--this way, when we're connected
  479.        to ourself, we don't cause the client to sent a DISCONNECT back
  480.        to us after we've closed the socket */
  481.     Delay(15);
  482.     
  483.     /* Tell AmiPhone we're outta here */
  484.     if (BLocalAmiPhoneNotified == TRUE)
  485.     {
  486.         MyInfo.daemonTask = NULL;
  487.         SendMessageToClient(MSG_CONTROL_BYE);
  488.     }
  489.     
  490.     AllocPacketList(FALSE);
  491.     if (BAudioAvail == TRUE) 
  492.     {
  493.         ulPhonedMask &= ~((1L << port1->mp_SigBit) | (1L << port2->mp_SigBit));
  494.         AllocAudio(FALSE);
  495.         BAudioAvail = FALSE;
  496.     }
  497.              
  498.     if (ngExitVal > RETURN_OK)
  499.     {
  500.         printf("CleanExit: [%s] (exit code %i)\n", szExitMessage, ngExitVal);    
  501.     
  502.     #ifdef DEBUG_FLAG
  503.         if (fpDebug) 
  504.         {
  505.             fprintf(fpDebug,"CleanExit: [%s] (exit code %i)\n", szExitMessage, ngExitVal);    
  506.             fflush(fpDebug);
  507.         }
  508.     #endif
  509.     }
  510.  
  511.     SetupTCPQueue(CLIENT_TCP_QUEUE, FALSE);
  512.             
  513.     if ((IntuitionBase)&&(ngExitVal > RETURN_WARN))
  514.     {
  515.         sprintf(szBuf,"Exit (Code %i)", ngExitVal);
  516.         DMakeReq(NULL,szExitMessage, szBuf);
  517.     }
  518.  
  519.     OpenLibraries(FALSE);        /* close all libraries */
  520.         
  521. #ifdef DEBUG_FLAG
  522.     if (ngExitVal > RETURN_OK) Delay(100);    /* so we can read the error */
  523.     if (fpDebug != NULL) fclose(fpDebug);
  524. #endif
  525. }
  526.  
  527.  
  528. char * OpenLibraries(BOOL BOpen)
  529. {
  530.     static char szError[30]="";
  531.     
  532.     if (BOpen == TRUE)
  533.     {
  534.         if ((GfxBase       = OpenLibrary("graphics.library",0L))  == NULL) return("graphics");
  535.         if ((IntuitionBase = OpenLibrary("intuition.library",37)) == NULL) return("intuition");
  536.         if ((SocketBase    = OpenLibrary("bsdsocket.library", 2)) == NULL) return("bsdsocket");
  537.         if ((IconBase      = OpenLibrary("icon.library", 33))     == NULL) return("icon");
  538.         if ((GadToolsBase  = OpenLibrary("gadtools.library", 36)) == NULL) return("gadtools");
  539.             
  540.         /* success */
  541.         return(NULL);
  542.     }
  543.     else
  544.     {
  545.         if (GadToolsBase  != NULL) CloseLibrary(GadToolsBase);
  546.         if (IconBase      != NULL) CloseLibrary(IconBase);
  547.         if (IntuitionBase != NULL) CloseLibrary(IntuitionBase);
  548.         if (SocketBase       != NULL) CloseLibrary(SocketBase);
  549.         if (GfxBase      != NULL) CloseLibrary((struct Library *)GfxBase);
  550.         return(NULL);
  551.     }
  552.  
  553.     return(NULL);
  554. }
  555.  
  556. void debug(int i)
  557. {
  558.     #ifdef DEBUG_FLAG
  559.         fprintf(fpDebug,"Waiting at debug point: [%i]\n",i);
  560.         fflush(fpDebug);
  561.         Delay(20);
  562.     #endif
  563. }
  564.  
  565.  
  566. /* returns true if a data packet was received, else false. */
  567. BOOL ReceiveUDPPacket(struct AmiPhoneSendBuffer * pPack)
  568. {
  569.     LONG ulAddressSize = sizeof(struct sockaddr_in);
  570.     LONG ulBytesRead;
  571.     int i;
  572.     
  573.     #ifdef DEBUG_FLAG
  574.         if (pPack == NULL) DEBUG("ReceiveUDPPacket:  NULL packet!\n")
  575.     #endif
  576.  
  577.     ulBytesRead = recvfrom(sUDPSocket,(UBYTE *)pPack,sizeof(struct AmiPhoneSendBuffer), 0L, &saUDPSocket, &ulAddressSize);
  578.     if (ulBytesRead == (sizeof(struct AmiPhonePacketHeader) + pPack->header.ulDataLen))
  579.     {
  580.         MyInfo.ulLastPacketSize += pPack->header.ulDataLen;
  581.  
  582.         if (pPack->header.ubCommand == PHONECOMMAND_DATA) 
  583.         {
  584.             lPlayUpTo = -1L;        /* No waiting if we've got UDP! */
  585.             QueueData(&pPack->header,pPack->ubData);
  586.         }
  587.         else
  588.         {
  589.             /* Tell AmiPhone client we saw an error */
  590.             MyInfo.BErrorR |= TRUE;
  591.  
  592.             #ifdef DEBUG_FLAG
  593.                 fprintf(fpDebug,"ReceiveUDPPacket:  unacceptable (non-data) UDP packet, type %i %c\n",pPack->header.ubCommand,pPack->header.ubCommand);
  594.                 fflush(fpDebug);
  595.             #endif
  596.             return(FALSE);
  597.         }    
  598.     
  599.         /* If we have any relay children, forward the packet to them too */
  600.         for (i=0;i<10;i++)
  601.         {
  602.             if (sRelayUDPSocket[i] != -1) 
  603.             {
  604.                 #ifdef DEBUG_FLAG
  605.                 fprintf(fpDebug,"Relaying UDP packet %i ('%c') to child %i [%s]\n",pPack->header.lSeqNum, pPack->header.ubCommand, i, szRelayName[i]); fflush(fpDebug);
  606.                 #endif
  607.                 send(sRelayUDPSocket[i], (UBYTE *)pPack, (sizeof(struct AmiPhonePacketHeader) + pPack->header.ulDataLen), 0L);
  608.             }
  609.         }
  610.     }
  611.     if (AUDIO_EMPTY) SetWindowTitle(NULL);
  612.     return(TRUE);
  613. }    
  614.  
  615.  
  616. /* Recv() in, parse, and act on the new command data */
  617. BOOL ReceiveTCPPacket(void)
  618. {
  619.     struct AmiPhoneSendBuffer * packet;
  620.     struct AmiPhonePacketHeader * cph;
  621.     
  622.     UNLESS(packet = GetTCPPacket(sTCPSocket)) return(FALSE);
  623.     switch(packet->header.ubCommand)
  624.     {
  625.         case PHONECOMMAND_DISCONNECT:
  626.             UNLESS(BNetConnect) return(FALSE);
  627.             BNetConnect = FALSE;
  628.             BDone = TRUE;    /* Get us outta here! */
  629.             break;
  630.  
  631.         case PHONECOMMAND_VWARN:
  632.             CheckVersions(BImARelay ? "AmiPhoned relay server" : "AmiPhone client", packet->header.ulBPS, UserHere());
  633.             break;
  634.  
  635.         case PHONECOMMAND_FLUSH:
  636.             nQMode = QMODE_FLUSH;    /* Start playback now */
  637.             lPlayUpTo = ((PacketList->lh_Tail) && 
  638.                          (cph = (struct AmiPhonePacketHeader *) PacketList->lh_Tail->ln_Name))
  639.                             ? cph->lSeqNum : -1L;
  640.             PlayNextPacket();
  641.             break;
  642.         
  643.         case PHONECOMMAND_CONNECT:
  644.             if (BNetConnect) return(FALSE);
  645.             
  646.             /* If we're a relay, here's where we store that info */
  647.             if (packet->header.ubType == PCCONNECT_RELAY) BImARelay = TRUE;
  648.  
  649.             #ifdef DEBUG_FLAG
  650.             fprintf(fpDebug,"Connecting party is using client v%i.%i, server is v%i.%i\n",
  651.                 packet->header.ulJoinCode/100,packet->header.ulJoinCode%100,VERSION_NUMBER/100,VERSION_NUMBER%100); fflush(fpDebug);
  652.             #endif
  653.             
  654.             if (CheckVersions(BImARelay ? "AmiPhoned relay server" : "AmiPhone client", packet->header.ulJoinCode, UserHere())) BSendWarningBack = TRUE;
  655.                                 
  656.             ulKeyCode = packet->header.ulBPS;
  657.             BNetConnect = TRUE;
  658.             break;
  659.             
  660.         case PHONECOMMAND_DATA:
  661.             /* We're receiving reliable/batch data.  Queue it, 
  662.                but don't start playing it until we receive the 
  663.                "go ahead" FLUSH packet. */
  664.             if (lPlayUpTo == -1L) lPlayUpTo = (packet->header.lSeqNum > 0L) ? (packet->header.lSeqNum-1) : 0L;
  665.             QueueData(&packet->header, packet->ubData);
  666.             SetWindowTitle(NULL);
  667.             MyInfo.ulLastPacketSize += packet->header.ulDataLen;
  668.             break;
  669.             
  670.         default:
  671.             #ifdef DEBUG_FLAG
  672.             fprintf(fpDebug,"ReceiveTCPPacket:  unknown command type %i [%c]\n",packet->header.ubCommand,packet->header.ubCommand);
  673.             fflush(fpDebug);
  674.             #endif
  675.             return(FALSE);
  676.             break;    
  677.     }    
  678.     return(TRUE);
  679. }
  680.  
  681.  
  682.  
  683.  
  684.  
  685.  
  686.  
  687.  
  688.  
  689. void QueueData(struct AmiPhonePacketHeader * pHead, UBYTE * ubData)
  690. {        
  691.     struct AmiPhonePacketHeader * newPacket;
  692.     ULONG ulDecompSize;
  693.     static ULONG ulLastPacketSeqNum = 0L;
  694.     
  695.     #ifdef DEBUG_FLAG
  696.         if (pHead  == NULL) DEBUG("QueueData:  NULL pHead!\n")
  697.         if (ubData == NULL) DEBUG("QueueData:  NULL ubData!\n")
  698.     #endif
  699.     
  700.     /* tell AmiPhone what kind of compression we're seeing */
  701.     MyInfo.ubCurrComp = pHead->ubType;
  702.     
  703.     /* If we've got an outdated packet, we're closing down, or our queue is full, no sense in adding it */
  704.     if (pHead->lSeqNum <= ulLowIndex)
  705.     {        
  706.         /* Tell AmiPhone client we saw an error */
  707.         MyInfo.BErrorR |= TRUE;    
  708.         return;    
  709.     }
  710.     UNLESS(BNetConnect) return;
  711.     
  712.     /* Figure out how much memory we'll need for the decompression,
  713.        based on the algorithm we're using. */
  714.     switch(pHead->ubType)
  715.     {
  716.         case COMPRESS_NONE:    ulDecompSize = pHead->ulDataLen;     break;    /* 1:1 decompression  */
  717.         case COMPRESS_ADPCM2:    ulDecompSize = (pHead->ulDataLen*4);    break;    /* 1:4 decompression  */
  718.         case COMPRESS_ADPCM3:    ulDecompSize = (pHead->ulDataLen*8/3);     break;    /* 3:8 decompression  */
  719.         default:        DEBUG("QueueData:  bad algorithm\n")
  720.                     return;
  721.                     break;
  722.     }
  723.     
  724.     /* make the size of the data even, so the audio hardware will like it better */
  725.     if (ulDecompSize % 2) ulDecompSize++;
  726.     
  727.     newPacket = AllocMem(sizeof(struct AmiPhonePacketHeader)+ulDecompSize, MEMF_CHIP);
  728.     if (newPacket == NULL) 
  729.     {
  730.         #ifdef DEBUG_FLAG
  731.         DEBUG("QueueData: Couldn't get memory!\n")
  732.         #endif
  733.         return;
  734.     }
  735.     
  736.     /* copy over the header */
  737.     memcpy(newPacket, pHead, sizeof(struct AmiPhonePacketHeader));
  738.     
  739.     /* If we are saving this data to disk, do so now */
  740.     if (BRecordMessage) 
  741.     {
  742.         UNLESS(fpOut) fpOut = OpenMessageFile(tTimeConnected, szMessageDir);
  743.         SavePacket(pHead,fpOut);
  744.     }
  745.     
  746.     /* Now decompress the data and set the length field to reflect the new size */
  747.     newPacket->ulDataLen = DecompressData(
  748.                 (UBYTE *) (((UBYTE *)pHead) + sizeof(struct AmiPhonePacketHeader)),
  749.                 (UBYTE *) (((UBYTE *)newPacket) + sizeof(struct AmiPhonePacketHeader)),
  750.                 pHead->ubType, pHead->ulDataLen,
  751.                 pHead->ulJoinCode);
  752.  
  753.     AddPacket((struct AmiPhoneSendBuffer *)newPacket);
  754.  
  755.     ulLastPacketSeqNum = pHead->lSeqNum;
  756.     
  757.     /* try to avoid an overflow if we're storing a large stream w/o playing! */
  758.     if ((AUDIO_EMPTY)&&(AvailMem(MEMF_CHIP) < MIN_CHIP_MEMORY)) PlayNextPacket();
  759. }
  760.  
  761.  
  762. /* Replace all cFrom's in szString with cTo's */
  763. void ReplaceChars(char * szString, char cFrom, char cTo)
  764. {
  765.     char * pcTemp;
  766.     
  767.     while(pcTemp = strchr(szString,cFrom)) *pcTemp = cTo;
  768. }
  769.  
  770.  
  771.  
  772. BOOL SafePutToPort(struct Message * message, char * portname)
  773. {    
  774.     struct MsgPort * dport;
  775.     
  776.     Forbid();        
  777.     dport = FindPort(portname);
  778.     
  779.     /* Only put a message if we have one--that way, we can pass in
  780.        NULL just to see if the port exists */
  781.     if ((dport)&&(message)) PutMsg(dport, message);
  782.     
  783.     Permit();
  784.     
  785.     return(dport ? TRUE : FALSE);
  786. }
  787.  
  788.  
  789. char * AmiPhonePortName(void)
  790. {
  791.     static char szPortName[30];
  792.     
  793.     /* Open a local message port as something AmiPhoned can find */
  794.     sprintf(szPortName,"AmiPhone_%ld",ulKeyCode);
  795.     
  796.     #ifdef DEBUG_FLAG
  797.     fprintf(fpDebug,"Looking for port: [%s]\n",szPortName);
  798.     fflush(fpDebug);
  799.     #endif
  800.     
  801.     return(szPortName);
  802. }
  803.  
  804. BOOL CreatePhonedMenus(BOOL BCreate)
  805. {   
  806.     void * VisualInfo = NULL;
  807.     int i;
  808.     
  809.     if (BCreate == FALSE) 
  810.     {
  811.         if (Menu != NULL) 
  812.         {
  813.             FreeMenus(Menu);
  814.             Menu = NULL;
  815.         }
  816.         return(TRUE);
  817.     }
  818.  
  819.     UNLESS((AmiPhonedScreen)&&(AmiPhonedWindow)) return(FALSE);    
  820.  
  821.     /* Create menus */    
  822.     UNLESS(Menu = CreateMenus(nmMenus, TAG_DONE)) return(FALSE);
  823.     UNLESS(VisualInfo = GetVisualInfo(AmiPhonedScreen, TAG_END))
  824.     {
  825.         FreeMenus(Menu); Menu = NULL;
  826.         return(FALSE);
  827.     }
  828.     
  829.     if (LayoutMenus(Menu, VisualInfo, TAG_DONE))
  830.     {
  831.         /* Update the menus */
  832.         for (i=0;i<10;i++) ReplaceMenuString(i);
  833.  
  834.         SetMenuStrip(AmiPhonedWindow, Menu);
  835.     }
  836.     else
  837.     {
  838.         FreeVisualInfo(VisualInfo);
  839.         FreeMenus(Menu); Menu = NULL;
  840.         return(FALSE);
  841.     }
  842.     FreeVisualInfo(VisualInfo);
  843.     
  844.     SetMenuValues();
  845.     return(TRUE);
  846. }
  847.  
  848. void LowerCase(char *sOldString)
  849. {
  850.     char *i = sOldString;
  851.     const int diff = 'a' - 'A';
  852.  
  853.     if (sOldString == NULL) return();
  854.      while (*i != '\0')
  855.      {
  856.                if ((*i >= 'A')&&(*i <= 'Z')) *i += diff;
  857.                 i++;
  858.      }
  859.      return;
  860. }
  861.  
  862.  
  863. void AddRelay(char * szOptIPName, int nWhich)
  864. {
  865.     char szTemp[100];
  866.     char * szNewString = NULL;
  867.     
  868.     UNLESS(AmiPhonedWindow) return;
  869.     UNLESS(Menu) return;
  870.     UNLESS(SetupTCPQueue(nWhich, TRUE)) return;
  871.     
  872.     *szTemp = '\0';
  873.         
  874.     if (szOptIPName) Strncpy(szTemp, szOptIPName, sizeof(szTemp));
  875.             else UNLESS(GetUserString(AmiPhonedScreen, AmiPhonedWindow, szTemp, "Add a Relay IP", "Enter the Name of the site to relay to", sizeof(szTemp))) return;
  876.  
  877.     if (strlen(szTemp) < 1) return;
  878.  
  879.     /* must be lower case */
  880.     LowerCase(szTemp);
  881.  
  882.     /* ignore any user@'s */
  883.     szNewString = strrchr(szTemp,'@');
  884.     if (szNewString == NULL) szNewString = szTemp; else szNewString++;
  885.  
  886.     /* translate "localhost" to our actual name--I get problems otherwise :( */
  887.     if (strcmp(szNewString,"localhost") == 0) 
  888.     {
  889.         if (gethostname(szTemp,sizeof(szTemp)) < 0) return;
  890.         szNewString = szTemp;
  891.     }
  892.     
  893.     ConnectRelay(szNewString, nWhich);
  894.     
  895.     /* Update the menus */
  896.     ReplaceMenuString(nWhich);
  897.     
  898.     /* Restore original title */
  899.     SetWindowTitle(NULL);
  900. }
  901.  
  902.  
  903. /* Based on current socket info, replaces the given item in the Relay
  904.    menu with what it should be. */
  905. void ReplaceMenuString(int nWhich)
  906. {
  907.     char * pcOldString, * pcTemp;
  908.         
  909.     UNLESS((Menu)&&(AmiPhonedWindow)) return;    
  910.  
  911.     ClearMenuStrip(AmiPhonedWindow);
  912.     UNLESS(pcOldString = ((struct IntuiText *)(GetRelayItem(nWhich)->ItemFill))->IText) 
  913.     {
  914.         #ifdef DEBUG_FLAG
  915.             fprintf(fpDebug,"ReplaceMenuString:  Menu String %i not found!\n"); fflush(fpDebug);
  916.         #endif
  917.         return;
  918.     }
  919.     
  920.     if (sRelayTCPSocket[nWhich] == -1)
  921.     {
  922.         if (nWhich == 9) nWhich = -1;
  923.         sprintf(pcOldString,"-Add Relay #%i-", nWhich+1);
  924.     }
  925.     else
  926.     {
  927.         if (sRelayUDPSocket[nWhich] != -1)
  928.         {
  929.             Strncpy(pcOldString,szRelayName[nWhich],MAXRELAYNAMELEN);                
  930.             /* cut it off at the first '.' */
  931.             if (pcOldString = strchr(pcOldString,'.')) *pcOldString = '\0';    
  932.         }
  933.         else
  934.         {
  935.             *pcOldString = '(';
  936.             Strncpy(pcOldString+1,szRelayName[nWhich],MAXRELAYNAMELEN-2);
  937.             /* cut it off at the first '.' */
  938.             if (pcTemp = strchr(pcOldString,'.')) *pcTemp = '\0';    
  939.             strncat(pcOldString,")",MAXRELAYNAMELEN-1);
  940.         }        
  941.     }
  942.     ResetMenuStrip(AmiPhonedWindow,Menu);
  943. }
  944.  
  945.  
  946. void RemoveRelay(int nWhich, BOOL BSendDisconnect)
  947. {
  948.     struct sockaddr_in saNullAddress;
  949.  
  950.     /* If there is no TCP socket, there's nothing to remove! */
  951.     if (sRelayTCPSocket[nWhich] == -1) return;
  952.  
  953.     if (BSendDisconnect)
  954.     {
  955.         #ifdef DEBUG_FLAG
  956.         fprintf(fpDebug,"RemoveRelay: Sending disconnect to socket %i (nWhich==%i)\n",sRelayTCPSocket[nWhich],nWhich);
  957.         fflush(fpDebug);
  958.         #endif
  959.  
  960.         UNLESS(SendRelayCommandPacket(PHONECOMMAND_DISCONNECT, 0, 0L, nWhich))
  961.         {
  962.             #ifdef DEBUG_FLAG
  963.             fprintf(fpDebug,"RemoveRelay:  Couldn't send disconnect packet to socket %i.\n",nWhich); fflush(fpDebug);
  964.             #endif
  965.         }
  966.     }
  967.  
  968.     /* Close the data socket if it's open */
  969.     if (sRelayUDPSocket[nWhich] != -1)
  970.     {
  971.         saNullAddress.sin_family = AF_UNSPEC;    /* to cause a disconnect */
  972.         connect(sRelayUDPSocket[nWhich], &saNullAddress, sizeof(saNullAddress));
  973.         CloseSocket(sRelayUDPSocket[nWhich]);
  974.         sRelayUDPSocket[nWhich] = -1;
  975.     }
  976.  
  977.     /* Get rid of buffers */
  978.     SetupTCPQueue(nWhich, FALSE);
  979.     
  980.     /* Close the TCP socket */
  981.     CloseSocket(sRelayTCPSocket[nWhich]);
  982.     sRelayTCPSocket[nWhich] = -1;
  983.  
  984.     /* Get back our memory for the internal IP name string */
  985.     FreeMem(szRelayName[nWhich],strlen(szRelayName[nWhich])+1);
  986.     szRelayName[nWhich] = NULL;
  987.         
  988.     /* Update Menus */
  989.     ReplaceMenuString(nWhich);
  990. }
  991.  
  992.  
  993. struct MenuItem * GetRelayItem(int nWhich)
  994. {
  995.     struct MenuItem * currentItem;
  996.     
  997.     UNLESS(Menu) return(NULL);
  998.     
  999.     currentItem = ((struct Menu *)(Menu->NextMenu))->FirstItem;
  1000.         
  1001.     /* Find the nWhich'thd item of the Relay menu */
  1002.     while (nWhich--) currentItem = currentItem->NextItem;
  1003.  
  1004.     return currentItem;
  1005. }
  1006.  
  1007.  
  1008. /* Sends out a "CONNECT_RELAY" packet */ 
  1009. int ConnectRelay(char * szIPName, int nWhich)
  1010. {
  1011.     int nTemp;
  1012.     LONG lTrue = TRUE;
  1013.     struct servent * sp;
  1014.     struct hostent * hp;
  1015.     const char szConnectType[] = "tcp";
  1016.     char szMessage[100];
  1017.     
  1018.     #ifdef DEBUG_FLAG
  1019.     if (szRelayName[nWhich]) 
  1020.     {
  1021.         fprintf(fpDebug,"ConnectRelay:  Warning!  Overwriting #%i, [%s]\n",nWhich,szRelayName[nWhich]);
  1022.         fflush(fpDebug);
  1023.     }
  1024.     #endif
  1025.  
  1026.     /* Record the IP of this relay */    
  1027.     nTemp = strlen(szIPName)+1;
  1028.     UNLESS(szRelayName[nWhich] = AllocMem(nTemp,MEMF_ANY)) return(FALSE);
  1029.     Strncpy(szRelayName[nWhich],szIPName,nTemp);    
  1030.     
  1031.         SetErrnoPtr(&errno, sizeof(errno));
  1032.             sp = getservbyname("AmiPhone",szConnectType);
  1033.     if (sp == NULL) sp = getservbyname("Amiphone",szConnectType);    /* Try almost all lowercase then! */    
  1034.     if (sp == NULL) sp = getservbyname("amiPhone",szConnectType);    /* Try almost all lowercase then! */    
  1035.     if (sp == NULL) sp = getservbyname("amiphone",szConnectType);    /* Try all lowercase then! */    
  1036.     if (sp == NULL)
  1037.     {
  1038.         DEBUG("Couldn't find AmiPhone service.\n")
  1039.         return(FALSE);
  1040.     }
  1041.     port = sp->s_port;
  1042.     
  1043.     sprintf(szMessage,"Finding [%s]",szIPName);
  1044.     SetWindowTitle(szMessage);
  1045.     
  1046.     if ((hp = gethostbyname(szIPName)) == NULL)
  1047.     {
  1048.         DEBUG("gethostbyname() failed.\n")
  1049.         return(FALSE);
  1050.     }
  1051.     bzero(&saRelayTCPAddress[nWhich], sizeof(struct sockaddr_in));
  1052.     bzero(&saRelayUDPAddress[nWhich], sizeof(struct sockaddr_in));
  1053.  
  1054.         bcopy(hp->h_addr, (char *)&(saRelayTCPAddress[nWhich].sin_addr), hp->h_length);
  1055.         bcopy(hp->h_addr, (char *)&(saRelayUDPAddress[nWhich].sin_addr), hp->h_length);
  1056.  
  1057.     saRelayTCPAddress[nWhich].sin_family = hp->h_addrtype;
  1058.     saRelayUDPAddress[nWhich].sin_family = hp->h_addrtype;
  1059.  
  1060.     saRelayTCPAddress[nWhich].sin_port   = htons(port);    
  1061.     /* UDP address to be discovered later */
  1062.     
  1063.     sRelayTCPSocket[nWhich] = socket(hp->h_addrtype,SOCK_STREAM,0);
  1064.     if (sRelayTCPSocket[nWhich] < 0)
  1065.     {
  1066.         SetWindowTitle("Socket(TCP) failed.");
  1067.         return(FALSE);
  1068.     }
  1069.     sRelayUDPSocket[nWhich] = socket(hp->h_addrtype,SOCK_DGRAM,0);
  1070.     if (sRelayUDPSocket[nWhich] < 0)
  1071.     {
  1072.         SetWindowTitle("Socket(UDP) failed.");
  1073.         return(FALSE);
  1074.     }
  1075.  
  1076.     sprintf(szMessage,"Contacting [%s]",szIPName);
  1077.     SetWindowTitle(szMessage);
  1078.     
  1079.     if (connect(sRelayTCPSocket[nWhich], (struct sockaddr *) &saRelayTCPAddress[nWhich], sizeof(struct sockaddr_in)) < 0)
  1080.     {
  1081.         SetWindowTitle("Relay connect refused.");
  1082.         return(FALSE);
  1083.     }
  1084.     
  1085.     /* Set socket to non-blocking */
  1086.     IoctlSocket(sRelayTCPSocket[nWhich], FIONBIO, (char*)&lTrue);
  1087.  
  1088.     if (SendRelayCommandPacket(PHONECOMMAND_CONNECT, PCCONNECT_RELAY, 0L, nWhich) == FALSE)
  1089.     {
  1090.         SetWindowTitle("Relay init failed.");
  1091.         return(FALSE);
  1092.     }    
  1093.     return(TRUE);
  1094. }
  1095.  
  1096.  
  1097. /* This function sends the given command packet over the link.  */
  1098. BOOL SendRelayCommandPacket(UBYTE ubCommand, UBYTE ubType, ULONG ulData, int nQNum)
  1099. {
  1100.     struct AmiPhonePacketHeader AmiPack;
  1101.     
  1102.     AmiPack.ubCommand = ubCommand;
  1103.     AmiPack.ubType      = ubType;
  1104.     AmiPack.ulBPS      = ulData;
  1105.     AmiPack.ulDataLen = 0L;
  1106.  
  1107.     if (ubCommand == PHONECOMMAND_CONNECT) AmiPack.ulJoinCode = VERSION_NUMBER;    
  1108.     AttemptTCPSend(sRelayTCPSocket[nQNum], nQNum, (UBYTE *) (&AmiPack), sizeof(AmiPack));
  1109.     return(TRUE);
  1110. }
  1111.  
  1112.  
  1113. /* Send a packet consisting of the given header, plus ulDataLen bytes
  1114.    that are located after it. */
  1115. BOOL SendRelayDataPacket(struct AmiPhoneSendBuffer * pPack, ULONG sSocket)
  1116. {
  1117.     ULONG lSendLen;
  1118.     
  1119.     if (pPack == NULL) return(FALSE);
  1120.     lSendLen = pPack->header.ulDataLen + sizeof(struct AmiPhonePacketHeader);
  1121.     return(send(sSocket, (UBYTE *)pPack, lSendLen, 0L) == lSendLen);
  1122. }
  1123.  
  1124. void IncrementBuildup(int nDelta)
  1125. {
  1126.     char szTemp[40];
  1127.     
  1128.     nMinReserve += nDelta;
  1129.     if (nMinReserve < 0) nMinReserve = 0;
  1130.     
  1131.     sprintf(szTemp,"UDP Delay: [%i.%is]",(nMinReserve/1000),(nMinReserve%1000)/100);
  1132.     SetWindowTitle(szTemp);
  1133. }
  1134.  
  1135.  
  1136. void CheckDaemonInfo(void)
  1137. {
  1138.     /* See if AmiPhone wants us to change priority */
  1139.     if (MyInfo.nPri != nPri) 
  1140.     {
  1141.         nPri = MyInfo.nPri;
  1142.         SetTaskPri(FindTask(NULL), nPri);    
  1143.     }
  1144.     
  1145.     /* Also see if AmiPhone wants us to open or close our window */
  1146.     if (MyInfo.BWantWindowOpen == TRUE)
  1147.     {
  1148.         OpenTitleBar(&ulPhonedMask);
  1149.     }
  1150.     if (MyInfo.BWantWindowOpen == FALSE)
  1151.     {
  1152.         CloseTitleBar(&ulPhonedMask);
  1153.     }
  1154. }
  1155.  
  1156.  
  1157. void PhonedWait(ULONG ulStdMask)
  1158. {
  1159.     static struct fd_set fsReadSet, fsWriteSet;
  1160.     ULONG ulMask;
  1161.     UBYTE * ubTemp;
  1162.     int nMaxPort = -1,i;
  1163.     struct IntuiMessage *msg;
  1164.     ULONG ulClass, ulCode, ulItemCode;
  1165.     struct MenuItem * mItem;
  1166.         
  1167.     FD_ZERO(&fsReadSet);              /* Initialize socket read set */
  1168.     FD_ZERO(&fsWriteSet);              /* Initialize socket read set */
  1169.     
  1170.     /* reset timer mask */
  1171.     ulMask = ulStdMask;
  1172.     
  1173.     /* FD_SET for each of the sockets in use, and find the Max Socket. */
  1174.     if (sTCPSocket != -1) 
  1175.     {
  1176.         FD_SET(sTCPSocket, &fsReadSet);        
  1177.         if (TCPQueueLength(CLIENT_TCP_QUEUE) > 0) FD_SET(sTCPSocket, &fsWriteSet);
  1178.         if (sTCPSocket > nMaxPort) nMaxPort = sTCPSocket;
  1179.     }
  1180.     if (sUDPSocket != -1) 
  1181.     {
  1182.         FD_SET(sUDPSocket, &fsReadSet);        
  1183.         if (sUDPSocket > nMaxPort) nMaxPort = sUDPSocket;
  1184.     }
  1185.     for (i=0;i<10;i++) 
  1186.     {
  1187.         if (sRelayTCPSocket[i] != -1) 
  1188.         {
  1189.             FD_SET(sRelayTCPSocket[i], &fsReadSet);
  1190.             if (TCPQueueLength(i) > 0) FD_SET(sRelayTCPSocket[i], &fsWriteSet);
  1191.             if (sRelayTCPSocket[i] > nMaxPort) nMaxPort = sRelayTCPSocket[i];
  1192.         }
  1193.         
  1194.         /* Don't need to listen on relay's UDP sockets because
  1195.            they're not allowed to send anything back on those */
  1196.     }
  1197.     
  1198.     /* Wait for Data to come in */
  1199.     /*         socket#     read        write        oob  timeout  other */
  1200.     WaitSelect(nMaxPort+1, &fsReadSet, &fsWriteSet, NULL, NULL,   &ulMask);
  1201.         
  1202.     CheckDaemonInfo();
  1203.  
  1204.     if (ulMask & SIGBREAKF_CTRL_E)
  1205.     {
  1206.         /* Toggle window state */
  1207.         if (AmiPhonedWindow) CloseTitleBar(&ulPhonedMask);
  1208.                     else OpenTitleBar(&ulPhonedMask);
  1209.     }    
  1210.     
  1211.     if ((port1)&&(ulMask & (1<<port1->mp_SigBit))) 
  1212.     {
  1213.         bStatus[0] = STATUS_INVALID;
  1214.         /* Now that the play is done, we can free the memory */    
  1215.         ubTemp = (UBYTE *) AIOptr1->ioa_Data;
  1216.         ubTemp -= sizeof(struct AmiPhonePacketHeader);
  1217.         FreePacket((struct AmiPhonePacketHeader *) ubTemp);
  1218.     
  1219.         while (GetMsg(port1)) {};    /* Clear the message port */
  1220.         PlayNextPacket();
  1221.     }
  1222.     
  1223.     if ((port2)&&(ulMask & (1<<port2->mp_SigBit))) 
  1224.     {
  1225.         bStatus[1] = STATUS_INVALID;
  1226.         /* Now that the play is done, we can free the memory */
  1227.         ubTemp = (UBYTE *) AIOptr2->ioa_Data;
  1228.         ubTemp -= sizeof(struct AmiPhonePacketHeader);
  1229.         FreePacket((struct AmiPhonePacketHeader *) ubTemp);
  1230.  
  1231.         while (GetMsg(port2)) {};    /* Clear the message port */
  1232.         PlayNextPacket();
  1233.     }
  1234.     
  1235.     if ((AmiPhonedWindow)&&(ulMask & (1<<AmiPhonedWindow->UserPort->mp_SigBit)))
  1236.     {
  1237.         if (msg = (struct IntuiMessage *) GetMsg(AmiPhonedWindow->UserPort))
  1238.         {
  1239.             ulClass = msg->Class;
  1240.             ulCode  = msg->Code;
  1241.             ReplyMsg((struct Message *) msg);
  1242.     
  1243.             switch(ulClass)
  1244.             {
  1245.                 case IDCMP_CLOSEWINDOW:
  1246.                     EXIT("User Disconnected",RETURN_OK)
  1247.                     break;
  1248.                     
  1249.                 case IDCMP_MENUPICK:
  1250.                     while( ulCode != MENUNULL ) 
  1251.                     {
  1252.                         mItem = ItemAddress( Menu, ulCode );
  1253.                         ulItemCode = (ULONG) GTMENUITEM_USERDATA(mItem);
  1254.                         if ((ulItemCode >= R_ADDRELAY)&&(ulItemCode <= R_ADDRELAY+9))
  1255.                         {
  1256.                             if (sRelayTCPSocket[ulItemCode-R_ADDRELAY] == -1) AddRelay(NULL,ulItemCode-R_ADDRELAY);
  1257.                                                     else RemoveRelay(ulItemCode-R_ADDRELAY,TRUE);
  1258.                         }
  1259.                         else switch(ulItemCode)
  1260.                         {
  1261.                             case P_LAUNCH:        LaunchXMitter(targethost);    break;
  1262.                             case P_INCREMENT:    IncrementBuildup(100);    break;
  1263.                             case P_DECREMENT:    IncrementBuildup(-100);    break;
  1264.                             case P_RECORD:        if (BRecordMessage) FinalizeOutFile();
  1265.                                         BRecordMessage = Not[BRecordMessage];
  1266.                                         break;
  1267.                             case P_ABOUT:         DisplayAbout();                break;
  1268.                             case P_FLUSHBUFFER:    lPlayUpTo = -1L; nQMode = QMODE_FLUSH; PlayNextPacket(); break;
  1269.                             case P_HIDEWINDOW:    CloseTitleBar(&ulPhonedMask);           break;
  1270.                             case P_QUIT:          EXIT("User Disconnected",RETURN_OK);       break;
  1271.                             default:         printf("Bad Menu Code:  %i\n",ulItemCode); break;
  1272.                         }
  1273.                         ulCode = mItem->NextSelect;
  1274.                     }
  1275.                     break;
  1276.             }
  1277.         }
  1278.     }
  1279.  
  1280.     if (FD_ISSET(sUDPSocket, &fsReadSet))    
  1281.     {
  1282.         ReceiveUDPPacket(&recBuffer);
  1283.         PlayNextPacket();    /* also try to play whenever we get new info */
  1284.     }
  1285.  
  1286.     if (FD_ISSET(sTCPSocket, &fsWriteSet)) ReduceTCPQueue(CLIENT_TCP_QUEUE, sTCPSocket);
  1287.     if (FD_ISSET(sTCPSocket, &fsReadSet))  ReceiveTCPPacket();
  1288.     
  1289.     for (i=0;i<10;i++) 
  1290.     {
  1291.         if (FD_ISSET(sRelayTCPSocket[i],&fsReadSet)) HandleRelayResponse(i);
  1292.         if (FD_ISSET(sRelayTCPSocket[i],&fsWriteSet)) ReduceTCPQueue(i, sRelayTCPSocket[i]);
  1293.     }
  1294.     
  1295.     if (ulMask & SIGBREAKF_CTRL_C) BDone = TRUE;
  1296.  
  1297.     SetMenuValues();
  1298. }
  1299.  
  1300. /* Update menus... actually this doesn't update the Relay menu, just Project for now */
  1301. void SetMenuValues(void)
  1302. {
  1303.     struct Menu *currentMenu = Menu;
  1304.     struct MenuItem *currentItem, *currentSub;
  1305.  
  1306.     UNLESS(currentMenu) return;
  1307.  
  1308.     if (AmiPhonedWindow) ClearMenuStrip(AmiPhonedWindow);
  1309.  
  1310.     /* Project Menu */
  1311.     FIRSTITEM;    if (BNoClient) ENABLEITEM; else DISABLEITEM;
  1312.     NEXTITEM;    /* Inc/dec submenu */
  1313.         FIRSTSUB;     /* Inc */
  1314.         NEXTSUB;    /* Dec */
  1315.         if (nMinReserve > 0) ENABLESUB; else DISABLESUB;
  1316.     NEXTITEM;    /* Record toggle */
  1317.     if (szMessageDir) ENABLEITEM; else DISABLEITEM;
  1318.     if (BRecordMessage) CHECKITEM; else UNCHECKITEM;
  1319.     NEXTITEM;    /* Flush Buffers */
  1320.     if (nQLength > 0) ENABLEITEM; else DISABLEITEM;
  1321.     
  1322.     if (AmiPhonedWindow) ResetMenuStrip(AmiPhonedWindow,Menu);
  1323. }
  1324.  
  1325.  
  1326. void PrintSocketState(struct sockaddr_in * psaSock)
  1327. {
  1328. #ifdef DEBUG_FLAG
  1329.     fprintf(fpDebug,"sin_family   =%d\n",psaSock->sin_family);
  1330.     fprintf(fpDebug,"sin_port     =%d\n",psaSock->sin_port);
  1331.     fprintf(fpDebug,"sin_sin_addr =%d\n",(ULONG)(psaSock->sin_addr));
  1332.     fprintf(fpDebug,"sin_zero     = %i %i %i %i %i %i %i %i\n",
  1333.             psaSock->sin_zero[0],
  1334.             psaSock->sin_zero[1],
  1335.             psaSock->sin_zero[2],
  1336.             psaSock->sin_zero[3],
  1337.             psaSock->sin_zero[4],
  1338.             psaSock->sin_zero[5],
  1339.             psaSock->sin_zero[6],
  1340.             psaSock->sin_zero[7]);
  1341.     fflush(fpDebug);
  1342. #endif
  1343. }
  1344.  
  1345.  
  1346. /* Called when we get a response.  Puts us in full-blown relay state! */
  1347. /* Changes the port to the final port (The one to use to send data)   */ 
  1348. void FinalizeRelay(int nWhich, int nPortNum, UBYTE ubReplyType, ULONG ulDataLen)
  1349. {
  1350.     int nSuccess;
  1351.     char szText[150];
  1352.         
  1353.     /* Change the conect port for this relay to what was specified */    
  1354.     saRelayUDPAddress[nWhich].sin_port = htons(nPortNum);
  1355.     nSuccess = connect(sRelayUDPSocket[nWhich], (struct sockaddr *) &saRelayUDPAddress[nWhich], sizeof(struct sockaddr_in));
  1356.     if (nSuccess < 0) 
  1357.     {    
  1358.         #ifdef DEBUG_FLAG
  1359.         fprintf(fpDebug,"FinalizeRelay: warning, reconnect failed: errno=%i\n",errno);
  1360.         fflush(fpDebug);
  1361.         #endif
  1362.     }
  1363.     if (ubReplyType == PCREPLY_CANTLEAVEMESSAGE)
  1364.     {
  1365.         DMakeReq(NULL,"This relay is not available, and their voice mail box is either full or disabled.",NULL);
  1366.         RemoveRelay(nWhich,FALSE);
  1367.         return;    
  1368.     }
  1369.     else if (ubReplyType == PCREPLY_LEAVEMESSAGE)
  1370.     {    
  1371.         sprintf(szText,"Your relay at %s is not available right now.\nWould you like to relay a message?  (%dk available)", szRelayName[nWhich], ulDataLen);
  1372.         UNLESS(DMakeReq(NULL,szText,"Leave Message|Cancel")) 
  1373.         {
  1374.             RemoveRelay(nWhich, TRUE);
  1375.             return;
  1376.         }
  1377.     }
  1378.     SetWindowTitle("Relay established.");
  1379.     ReplaceMenuString(nWhich);
  1380. }
  1381.  
  1382. void HandleRelayResponse(int nWhich)
  1383. {
  1384.     struct AmiPhonePacketHeader aphTemp;
  1385.     LONG ulAddressSize = sizeof(struct sockaddr_in);
  1386.     LONG ulBytesRead;
  1387.  
  1388.     #ifdef DEBUG_FLAG
  1389.         fprintf(fpDebug,"Handling response from Relay %i\n",nWhich); fflush(fpDebug);
  1390.     #endif
  1391.  
  1392.     /* Note:  Can't use GetTCPPacket() because it only has 1 static buffer... */
  1393.     ulBytesRead = recv(sRelayTCPSocket[nWhich],(UBYTE *)&aphTemp,sizeof(struct AmiPhonePacketHeader), 0L);
  1394.     if (ulBytesRead == sizeof(struct AmiPhonePacketHeader))
  1395.     {    
  1396.         switch(aphTemp.ubCommand)
  1397.         {            
  1398.             case PHONECOMMAND_DISCONNECT:
  1399.             case PHONECOMMAND_DENY:
  1400.                 SetWindowTitle("Relay denied.");
  1401.                 RemoveRelay(nWhich,FALSE);
  1402.                 break;
  1403.  
  1404.             case PHONECOMMAND_VWARN:
  1405.                 CheckVersions("AmiPhoned relay client", aphTemp.ulBPS, UserHere());
  1406.                 break;
  1407.                 
  1408.             case PHONECOMMAND_REPLY:
  1409.                 FinalizeRelay(nWhich, aphTemp.ulBPS, aphTemp.ubType, aphTemp.ulJoinCode);
  1410.                 break;
  1411.  
  1412.             default:
  1413.                 #ifdef DEBUG_FLAG
  1414.                     fprintf(fpDebug,"HandleRelayResponse:  unknown command type %i %c\n",aphTemp.ubCommand,aphTemp.ubCommand);
  1415.                     fflush(fpDebug);
  1416.                 #endif
  1417.                 break;    
  1418.         }
  1419.     } 
  1420.     else 
  1421.     {
  1422.         #ifdef DEBUG_FLAG
  1423.         fprintf(fpDebug,"Warning, packet size (ulBytesRead=%d) mismatch (should be %d)\n",
  1424.             ulBytesRead, sizeof(struct AmiPhonePacketHeader));
  1425.         fflush(fpDebug);
  1426.         #endif
  1427.     }
  1428. }
  1429.  
  1430.  
  1431. void ParseArgs(void)
  1432. {
  1433.     int nParam;
  1434.     char *szParam;
  1435.     char *pcAmiPhone = getenv("AMIPHONE");
  1436.     struct DiskObject *AmiPhoneIconDiskObject;
  1437.  
  1438.     if (pcAmiPhone == NULL) pcAmiPhone = "AmiTCP:bin/AmiPhone";    /* default */
  1439.     
  1440.     AmiPhoneIconDiskObject = GetDiskObject((UBYTE *)pcAmiPhone);
  1441.     if (AmiPhoneIconDiskObject == NULL) return;
  1442.  
  1443.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "AWAYVAR", &nParam, &szParam)) Strncpy(szAwayVar,szParam,sizeof(szAwayVar));
  1444.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "VOICEMAILDIR", &nParam, &szParam)) 
  1445.     {
  1446.         szMessageDir = AllocMem(strlen(szParam)+1,MEMF_ANY);
  1447.         if (szMessageDir != NULL) 
  1448.         {
  1449.             Strncpy(szMessageDir,szParam,strlen(szParam)+1);
  1450.             #ifdef DEBUG_FLAG
  1451.             fprintf(fpDebug,"Message Directory: [%s]\n",szParam); fflush(fpDebug);
  1452.             #endif
  1453.         }
  1454.     }
  1455.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "DAEMONLEFT", &nParam, &szParam)) windowleft = nParam;
  1456.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "DAEMONTOP",  &nParam, &szParam)) windowtop  = nParam;
  1457.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "MAXVOICEMAILSIZE", &nParam, &szParam)) nMaxVoiceMailDirSize = nParam;
  1458.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "MAXMESSAGESIZE", &nParam, &szParam))   nMaxMessageSize      = nParam;
  1459.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "STARTUPDELAY", &nParam, &szParam))   nMinReserve = nParam;
  1460.     
  1461.     if (GetToolTypeArg(AmiPhoneIconDiskObject, "SHOWDAEMON", &nParam, &szParam))
  1462.     {
  1463.         if ((*szParam=='n')||(*szParam=='N')) BOpenWindow = FALSE; else BOpenWindow = TRUE;
  1464.     }
  1465.     if ((AmiPhonedScreen == NULL)&&(GetToolTypeArg(AmiPhoneIconDiskObject, "PUBSCREEN",  &nParam, &szParam)))
  1466.         AmiPhonedScreen = LockPubScreen(szParam);
  1467.     else if ((AmiPhonedScreen == NULL)&&(GetToolTypeArg(AmiPhoneIconDiskObject, "PUBLICSCREEN",  &nParam, &szParam)))
  1468.         AmiPhonedScreen = LockPubScreen(szParam);
  1469.  
  1470.            FreeDiskObject(AmiPhoneIconDiskObject);    
  1471. }
  1472.  
  1473. void UpperCase(char *sOldString)
  1474. {
  1475.     char *i = sOldString;
  1476.     const int diff = 'a' - 'A';
  1477.  
  1478.     UNLESS(sOldString) return();
  1479.     
  1480.     while (*i != '\0')
  1481.     {
  1482.             if ((*i >= 'a')&&(*i <= 'z')) *i = *i - diff;
  1483.             i++;
  1484.      }
  1485.      return;
  1486. }
  1487.  
  1488. BOOL GetToolTypeArg(struct DiskObject * AmiPhoneIconDiskObject, char *szArg, int *nParam, char **szParam)
  1489. {
  1490.     static char sToolParam[200];
  1491.     char **toolarray = (char **) AmiPhoneIconDiskObject->do_ToolTypes;
  1492.     char *sTemp;
  1493.  
  1494.     /* Clear default string */
  1495.     sToolParam[0] = '\0';
  1496.     *szParam = sToolParam;    /* Return pointer to it */
  1497.             
  1498.     if ((toolarray != NULL) &&
  1499.         ((sTemp = (char *) FindToolType(toolarray,szArg)) != NULL))
  1500.     {
  1501.         *nParam = atoi(sTemp);
  1502.         Strncpy(sToolParam,sTemp,sizeof(sToolParam));
  1503.         return(TRUE);
  1504.     }                     
  1505.      return(FALSE);
  1506. }
  1507.  
  1508.  
  1509.  
  1510. void LaunchXMitter(char * szPeerName)
  1511. {
  1512.     char szCommand[350];
  1513.     ULONG ulResult;
  1514.     char * pcAmiPhone = getenv("AMIPHONE");
  1515.     char * pcTemp;
  1516.     
  1517.     if (pcAmiPhone == NULL) pcAmiPhone = "AmiTCP:bin/AmiPhone";
  1518.     
  1519.     sprintf(szCommand,"run %s %s _KEY=%lu|%lu", pcAmiPhone, szPeerName, ulKeyCode, (ULONG) (&MyInfo));
  1520.  
  1521.     /* strip out any EOL chars */
  1522.     while (pcTemp = strchr(szCommand,'\r')) *pcTemp = ' ';
  1523.     while (pcTemp = strchr(szCommand,'\n')) *pcTemp = ' ';
  1524.  
  1525. #ifdef DEBUG_FLAG
  1526.     fprintf(fpDebug,"executing: [%s] (MyInfo=%p)\n",szCommand,&MyInfo);
  1527.     fflush(fpDebug);
  1528. #endif    
  1529.     /* and... launch! */
  1530.     if ((ulResult = system(szCommand)) != 0)
  1531.     {
  1532.         #ifdef DEBUG_FLAG
  1533.             fprintf(fpDebug,"LaunchXMitter:  warning, client launch returned %d\n",ulResult);
  1534.             fflush(fpDebug);
  1535.         #endif
  1536.     }
  1537.     else BNoClient = FALSE;
  1538. }
  1539.  
  1540.  
  1541.  
  1542. void DisplayAbout(void)
  1543. {    
  1544.     char szMessage[300]="";
  1545.  
  1546.     sprintf(szMessage,"AmiPhoned v%i.%i%s\nby Jeremy Friesner\njfriesne@ucsd.edu\nCompiled: %s",
  1547.         VERSION_NUMBER/100, VERSION_NUMBER%100, 
  1548.         #ifdef DEBUG_FLAG
  1549.         "D",
  1550.         #else
  1551.         "",
  1552.         #endif
  1553.         __DATE__);
  1554.     DMakeReq(NULL,szMessage,"Okay");                
  1555. }
  1556.  
  1557.  
  1558. /* This is initialization info only! */
  1559. void SetUpLocalAmiPhoneInfo(struct AmiPhoneInfo * inf)
  1560. {
  1561.     inf->PhoneMsg.mn_Node.ln_Type     = NT_MESSAGE;
  1562.     inf->PhoneMsg.mn_Length     = sizeof(struct AmiPhoneInfo);
  1563.     inf->PhoneMsg.mn_ReplyPort        = NULL;
  1564.     inf->ubControl            = MSG_CONTROL_HI;
  1565.     inf->ubCurrComp            = COMPRESS_INVALID;
  1566.     inf->ulLastPacketSize        = 0L;
  1567.     inf->BErrorR            = FALSE;
  1568.     inf->nPri            = nPri;
  1569.     inf->BWantWindowOpen        = -1;  /* = no preference */
  1570.     inf->daemonTask            = FindTask(NULL);
  1571.     inf->BWindowIsOpen        = (AmiPhonedWindow != NULL);
  1572. }
  1573.  
  1574.  
  1575.  
  1576. /* Allocates the PacketList, or clears and frees it */
  1577. BOOL AllocPacketList(BOOL BAlloc)
  1578. {    
  1579.     if (BAlloc == TRUE)
  1580.     {        
  1581.         if (PacketList != NULL) return(FALSE);
  1582.         UNLESS(PacketList = AllocMem(sizeof(struct List),MEMF_CLEAR)) return(FALSE);
  1583.         NewList(PacketList);
  1584.     }
  1585.     else
  1586.     {
  1587.         struct Node * current;
  1588.         
  1589.         UNLESS(PacketList) return(FALSE);
  1590.         
  1591.         while(current = RemHead(PacketList))
  1592.         {
  1593.             FreePacket((struct AmiPhonePacketHeader *) current->ln_Name);
  1594.             FreeMem(current,sizeof(struct Node));
  1595.         }
  1596.         FreeMem(PacketList,sizeof(struct List));
  1597.         PacketList = NULL;
  1598.     }
  1599.     return(TRUE);
  1600. }
  1601.  
  1602.  
  1603. /* Will play the earliest numbered packet that is after ulLowIndex
  1604.    and delete any that came before it.  If it did play a (REAL)
  1605.    packet, it will increase ulLowIndex to be that packet number */
  1606. BOOL PlayNextPacket(void)
  1607. {
  1608.     struct Node * current;
  1609.     struct AmiPhonePacketHeader * cph;
  1610.     int nPlayPackets;        /* Number of packets to attempt to play before returning */
  1611.     ULONG ulNextIndex;
  1612.  
  1613.     if ((lPlayUpTo != -1L) && (PacketList->lh_Head) &&
  1614.         (cph = (struct AmiPhonePacketHeader *) PacketList->lh_Head->ln_Name) &&
  1615.         (cph->lSeqNum > lPlayUpTo)) return(FALSE);
  1616.         
  1617.     /* Determine how many packets should be set up to play */
  1618.          if (AUDIO_FULL)  return(FALSE);    /* Don't play if both slots are full */
  1619.     else if (AUDIO_HALF)  nPlayPackets = 1;    /* Play one packet if one is free    */
  1620.     else               nPlayPackets = 2; /* Play two packets if two are free  */
  1621.  
  1622.     /* If there are no more packets pending, and nobody is playing
  1623.        anything, then free the audio channel! */
  1624.     if ((nQLength == 0)&&(nPlayPackets == 2)&&(BAudioAvail == TRUE))
  1625.     {
  1626.         ulPhonedMask &= ~((1L << port1->mp_SigBit) | (1L << port2->mp_SigBit));
  1627.         AllocAudio(FALSE);
  1628.         BAudioAvail = FALSE;
  1629.     }
  1630.             
  1631.     /* One more check--if we hit empty, we want to fill back up
  1632.        before we start playing again; at least this will localize
  1633.        the annoyance to one large gap rather than many little ones! */
  1634.          if (nQLengthMS < nMinReserve)
  1635.          {
  1636.              /* If we're empty, we want to save up. */
  1637.              if (nQMode == QMODE_EMPTY) return(FALSE);
  1638.          }
  1639.          else nQMode = QMODE_FLUSH;   /* queue has enough packets, start draining! */
  1640.     
  1641.     while (current = RemHead(PacketList))            
  1642.     {
  1643.         nQLength--;
  1644.         cph = (struct AmiPhonePacketHeader*) current->ln_Name;
  1645.         nQLengthMS -= PacketTime(cph);
  1646.         FreeMem(current,sizeof(struct Node));
  1647.         /* Refresh window title to reflect the new length */
  1648.         SetWindowTitle(NULL);
  1649.         
  1650.         /* If the queue becomes empty, start storing up again */
  1651.         if (nQLength == 0) nQMode = QMODE_EMPTY;
  1652.  
  1653.         if (cph->lSeqNum <= ulLowIndex)
  1654.         {
  1655.             #ifdef DEBUG_FLAG
  1656.             fprintf(fpDebug,"PlayNextPacket: Packet (%d) was <= ulLowIndex (%d), killing it. (you should never see this message)\n",cph->lSeqNum, ulLowIndex);
  1657.             fflush(fpDebug);
  1658.             #endif
  1659.             
  1660.             /* Tell AmiPhone client we saw an error */
  1661.             MyInfo.BErrorR |= TRUE;
  1662.  
  1663.             FreePacket(cph);
  1664.         }
  1665.         else
  1666.         {
  1667.             /* Found the first higher-than-ulLowIndex item in the list.
  1668.                Since the list is sorted low-to-high, it should be the minimum. 
  1669.                Play it, and set ulLowIndex equal to it, then free it. 
  1670.                Then set the timer for the next piece. */
  1671.         
  1672.             /* Since PlayAudio may deallocate our packet, get this info now. */
  1673.             ulNextIndex = cph->lSeqNum;
  1674.  
  1675.             /* If we don't have an audio channel, get one! */
  1676.             if (BAudioAvail == FALSE) 
  1677.             {
  1678.                 BAudioAvail = AllocAudio(TRUE);
  1679.                 
  1680.                 /* To ensure any half-way allocs are free'd */
  1681.                 if (BAudioAvail == FALSE) 
  1682.                 {
  1683.                     /* Tell AmiPhone client we have an error */
  1684.                     MyInfo.BErrorR |= TRUE;
  1685.         
  1686.                     AllocAudio(FALSE);
  1687.                 }
  1688.                 else
  1689.                     ulPhonedMask |= ((1L << port1->mp_SigBit) | (1L << port2->mp_SigBit));
  1690.  
  1691.             }
  1692.     
  1693.             /* PlayAudio can handle it if there isn't BAudioAvail */                
  1694.             if (PlayAudio((struct AmiPhoneSendBuffer *)cph) == FALSE)
  1695.             {
  1696.                 DEBUG("PlayNextPacket: PlayAudio FAILED.\n")
  1697.             }
  1698.         
  1699.             /* raise the minimum requirement! */
  1700.             ulLowIndex = ulNextIndex;
  1701.  
  1702.             nPlayPackets--;
  1703.             if (nPlayPackets == 0) return(TRUE);
  1704.         }
  1705.     }
  1706.      return(TRUE);
  1707. }
  1708.  
  1709.  
  1710. /*  plays the given packet, if it can, changing the status[] appropriately  */
  1711. BOOL PlayAudio(struct AmiPhoneSendBuffer * packet)
  1712. {
  1713.     struct IOAudio * AIOptr;
  1714.     
  1715.     static LONG lTrackSeq = 0L;
  1716.     
  1717.     if (packet->header.lSeqNum != (lTrackSeq+1))
  1718.     {
  1719.         #ifdef DEBUG_FLAG
  1720.         fprintf(fpDebug,"Warning: packet noncontinuity [%d -> %d]\n",
  1721.             lTrackSeq, packet->header.lSeqNum);
  1722.         fflush(fpDebug);
  1723.         #endif
  1724.         
  1725.         /* Tell AmiPhone client we saw an error */
  1726.         MyInfo.BErrorR |= TRUE;
  1727.     }
  1728.     lTrackSeq = packet->header.lSeqNum;
  1729.  
  1730.     #ifdef DEBUG_FLAG
  1731.     fprintf(fpDebug,"Playing packet [%i], length=[%i], BPS=[%i]\n",
  1732.         packet->header.lSeqNum,packet->header.ulDataLen,packet->header.ulBPS);
  1733.     fflush(fpDebug);
  1734.     #endif
  1735.     
  1736.     if (packet == NULL)
  1737.     {
  1738.         DEBUG("PlayAudio: NULL packet\n")
  1739.         return(FALSE);
  1740.     }
  1741.  
  1742.     if (BAudioAvail == FALSE)
  1743.     {
  1744.         #ifdef DEBUG_FLAG
  1745.         fprintf(fpDebug,"No audio available, throwing away packet %lu\n",packet->header.lSeqNum); fflush(fpDebug);
  1746.         #endif
  1747.         
  1748.         /* since we can't play it, simply throw away this packet */
  1749.         FreePacket((struct AmiPhonePacketHeader *)packet);
  1750.         return(TRUE);
  1751.     }
  1752.         
  1753.     if (packet->header.ulBPS < MIN_SAMPLE_RATE) 
  1754.     {
  1755.         #ifdef DEBUG_FLAG
  1756.             fprintf(fpDebug,"PlayAudio:  play rate too low [%d]\n",packet->header.ulBPS);
  1757.         #endif    
  1758.         return(FALSE);
  1759.     }
  1760.     if (packet->header.ulDataLen < 1L) 
  1761.     {
  1762.         DEBUG("PlayAudio:  empty packet\n")            
  1763.         return(FALSE);
  1764.     }
  1765.     
  1766.     if (bStatus[0] == STATUS_INVALID) 
  1767.     {
  1768.         AIOptr=AIOptr1;
  1769.         bStatus[0] = STATUS_PLAYING;
  1770.     }
  1771.     else if (bStatus[1] == STATUS_INVALID)
  1772.     {
  1773.         AIOptr=AIOptr2;
  1774.         bStatus[1] = STATUS_PLAYING;
  1775.     }
  1776.     else 
  1777.     {
  1778.         DEBUG("PlayAudio:  no free channels\n")
  1779.         return(FALSE);
  1780.     }
  1781.     
  1782.     /* Fill out sample length, pointer to data, and playback speed */    
  1783.     AIOptr->ioa_Length = packet->header.ulDataLen;
  1784.     AIOptr->ioa_Data   = packet->ubData;
  1785.     AIOptr->ioa_Period = (UWORD) (SystemClock / packet->header.ulBPS);    
  1786.     
  1787.     BeginIO((struct IORequest *)AIOptr);    /* start playing sample */
  1788.     return(TRUE);
  1789. }
  1790.  
  1791.  
  1792.  
  1793.  
  1794.  
  1795. /* Deallocates memory for the given packet AND its associated data chunk */
  1796. void FreePacket(struct AmiPhonePacketHeader * cph)
  1797. {    
  1798.     #ifdef DEBUG_FLAG
  1799.     if (cph == NULL) 
  1800.     {    
  1801.         #ifdef DEBUG_FLAG
  1802.         fprintf(fpDebug,"FreePacket: NULL pointer!\n");
  1803.         #endif
  1804.         return;
  1805.     }
  1806.     #endif
  1807.  
  1808.     FreeMem(cph,sizeof(struct AmiPhonePacketHeader) + cph->ulDataLen);
  1809. }
  1810.  
  1811.  
  1812.  
  1813. #ifdef DEBUG_FLAG
  1814. void PrintPacketList(void)
  1815. {
  1816.     struct Node * current = PacketList->lh_Head;
  1817.     struct AmiPhonePacketHeader * aph;
  1818.     
  1819.     fprintf(fpDebug,"Packet List: nQLength = %i\n",nQLength);
  1820.     
  1821.     while (current->ln_Succ)
  1822.     {
  1823.         aph = (struct AmiPhonePacketHeader *)(current->ln_Name);
  1824.         if (aph == NULL) DEBUG("NULL NODE!!!")
  1825.         else
  1826.         fprintf(fpDebug,"Node: lSeq = %d, lLen = %d, lCom = %d lType = %d\n",
  1827.             aph->lSeqNum, aph->ulDataLen, aph->ubCommand, aph->ubType);
  1828.         current = current->ln_Succ;
  1829.     }
  1830. }
  1831. #endif
  1832.  
  1833.  
  1834. /* Will add the packet to the list, based on its SeqNum */
  1835. /* If the index is lower than ulLowIndex, we will cheerfully delete
  1836.    it and return TRUE anyway.  That we at least packets are never
  1837.    played out of order!  */
  1838. BOOL AddPacket(struct AmiPhoneSendBuffer * ubPacket)
  1839. {
  1840.     struct Node * newNode;
  1841.     struct Node *current=PacketList->lh_Head, *past;
  1842.     struct AmiPhonePacketHeader * nph, * cph;
  1843.     static LONG lHighestSeqNum = 0L;
  1844.     
  1845.     if (ubPacket->header.lSeqNum <= ulLowIndex) 
  1846.     {
  1847.         #ifdef DEBUG_FLAG
  1848.         fprintf(fpDebug,"AddPacket: Packet %d was below ulLowIndex %d, killing it.\n",ubPacket->header.lSeqNum, ulLowIndex);
  1849.         fflush(fpDebug);
  1850.         #endif
  1851.         
  1852.         /* Tell AmiPhone client we saw an error */
  1853.         MyInfo.BErrorR |= TRUE;
  1854.  
  1855.         FreePacket((struct AmiPhonePacketHeader *)ubPacket);
  1856.         return(TRUE);
  1857.     }
  1858.     
  1859.     if ((newNode = AllocMem(sizeof(struct Node), MEMF_CLEAR)) == NULL) return(FALSE);
  1860.     newNode->ln_Name = (char *) ubPacket;
  1861.  
  1862.     past = NULL;
  1863.     nph = (struct AmiPhonePacketHeader*) newNode->ln_Name;    
  1864.  
  1865.     /* Only do things the expensive way if the new packet isn't in order! */
  1866.     if (nph->lSeqNum < lHighestSeqNum)
  1867.     {
  1868.         /* Add the packet into the correct place in the list, based
  1869.            on its sequence number. */
  1870.         while (current->ln_Succ)
  1871.         {
  1872.             cph = (struct AmiPhonePacketHeader*) (current->ln_Name);
  1873.         
  1874.             if (cph->lSeqNum > nph->lSeqNum)
  1875.             {
  1876.                 Insert(PacketList, newNode, past);    /* and put it back in after current */
  1877.                 nQLength++;
  1878.                 nQLengthMS += PacketTime((struct AmiPhonePacketHeader *)ubPacket);
  1879.                 return(TRUE);
  1880.             }
  1881.             past = current;                /* step to next in list */
  1882.             current = current->ln_Succ;
  1883.         }
  1884.     }
  1885.     else
  1886.     {
  1887.         /* Otherwise add the packet directly to the end! */
  1888.         lHighestSeqNum = nph->lSeqNum;
  1889.         AddTail(PacketList,newNode);        /* If we've got to the end without returning, add it to the end */
  1890.         nQLength++;    
  1891.         nQLengthMS += PacketTime((struct AmiPhonePacketHeader *)ubPacket);
  1892.     }
  1893.     return(TRUE);
  1894. }
  1895.  
  1896.  
  1897.  
  1898. /* Opens a little title bar to give listening status, and to let the
  1899.    user close it if he wants to disconnect. */
  1900. void OpenTitleBar(ULONG * pulMask)
  1901. {
  1902.     char * pcTemp;
  1903.     char szTemp[100];
  1904.     
  1905.     if (AmiPhonedWindow != NULL) return;
  1906.         
  1907.     /* Get default pub screen if we don't already have one */
  1908.     if (AmiPhonedScreen == NULL) AmiPhonedScreen = LockPubScreen(NULL);
  1909.     if (AmiPhonedScreen == NULL) return;
  1910.  
  1911.     Strncpy(szShortPeerName, targethost, sizeof(szShortPeerName));
  1912.     if (pcTemp = strchr(szShortPeerName,'.')) *pcTemp = '\0';
  1913.  
  1914.     sprintf(szTemp,"AmiPhoned:[%s] [88.8s] +",szShortPeerName);
  1915.     nWindowWidth = TextLength(&AmiPhonedScreen->RastPort, szTemp, strlen(szTemp))+EXTRA_WINDOW_WIDTH;
  1916.     
  1917.     if (windowtop == -1)  windowtop    = 0;    
  1918.     if (windowleft == -1) windowleft   = (AmiPhonedScreen->Width - nWindowWidth)/2;
  1919.     
  1920.         if (AmiPhonedWindow = OpenWindowTags( NULL,
  1921.         WA_Left,        windowleft,
  1922.             WA_Top,         windowtop,
  1923.                    WA_Width,       nWindowWidth,
  1924.             WA_Height,      AmiPhonedScreen->Font->ta_YSize+3,
  1925.             WA_PubScreen,    AmiPhonedScreen,
  1926.             WA_IDCMP,       IDCMP_CLOSEWINDOW|IDCMP_MENUPICK,
  1927.             WA_Flags,       WFLG_SMART_REFRESH|WFLG_ACTIVATE|WFLG_CLOSEGADGET|
  1928.                             WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_NEWLOOKMENUS,
  1929.                WA_DepthGadget, TRUE,
  1930.                WA_CloseGadget, TRUE,
  1931.                WA_DragBar,    TRUE,
  1932.                WA_AutoAdjust,  TRUE,
  1933.                WA_Activate,    FALSE,
  1934.         TAG_DONE )) *pulMask |= 1L<<(AmiPhonedWindow->UserPort->mp_SigBit);
  1935.  
  1936.     SetWindowTitle(NULL);
  1937.     CreatePhonedMenus(TRUE);
  1938.     
  1939.     MyInfo.BWindowIsOpen = TRUE;
  1940.     MyInfo.BWantWindowOpen = -1;
  1941.     SendMessageToClient(MSG_CONTROL_UPDATE);
  1942. }
  1943.  
  1944.  
  1945. /* Sends a message and wait for reply */
  1946. BOOL SendMessageToClient(UBYTE ubMessage)
  1947. {
  1948.     char * szPortName = AmiPhonePortName();
  1949.     struct MsgPort * WaitForReplyAt = CreatePort(0,0);
  1950.     BOOL BMessageSent = FALSE;
  1951.     
  1952.     UNLESS(WaitForReplyAt) return(FALSE);
  1953.     
  1954.     MyInfo.PhoneMsg.mn_Node.ln_Type = NT_MESSAGE;
  1955.     MyInfo.PhoneMsg.mn_Length       = sizeof(struct AmiPhoneInfo);
  1956.     MyInfo.PhoneMsg.mn_ReplyPort    = WaitForReplyAt;
  1957.         
  1958.     MyInfo.ubControl = ubMessage;
  1959.     
  1960.     if (SafePutToPort((struct Message *)&MyInfo, szPortName)) 
  1961.     {
  1962.         BMessageSent = TRUE;
  1963.         WaitPort(WaitForReplyAt);
  1964.         BNoClient = FALSE;
  1965.     }
  1966.     else BNoClient = TRUE;    /* sniff--we must be all awone... */
  1967.     
  1968.     /* Okay to just straight-out delete this port because */
  1969.     /* we know that it is only going to be used for one reply msg */
  1970.     DeletePort(WaitForReplyAt);
  1971.     
  1972.     return(BMessageSent);
  1973. }
  1974.  
  1975.  
  1976.  
  1977. /* Closes the little title bar */
  1978. void CloseTitleBar(ULONG * pulMask)
  1979. {
  1980.     if (AmiPhonedWindow == NULL) return;
  1981.  
  1982.     windowtop  = AmiPhonedWindow->TopEdge;
  1983.     windowleft = AmiPhonedWindow->LeftEdge;
  1984.     
  1985.     *pulMask &= ~(1L<<(AmiPhonedWindow->UserPort->mp_SigBit));
  1986.     CloseWindow(AmiPhonedWindow);
  1987.     
  1988.     CreatePhonedMenus(FALSE);
  1989.     
  1990.     AmiPhonedWindow = NULL;
  1991.     MyInfo.BWindowIsOpen = FALSE;
  1992.     
  1993.     MyInfo.BWantWindowOpen = -1;
  1994.     SendMessageToClient(MSG_CONTROL_UPDATE);
  1995. }
  1996.  
  1997.  
  1998.  
  1999. /* returns TRUE if user is not marked away, FALSE if he is */
  2000. BOOL UserHere(void)
  2001. {
  2002.     char *szAway = NULL;
  2003.     
  2004.     if (szAwayVar) szAway = getenv(szAwayVar);
  2005.     
  2006.     #ifdef DEBUG_FLAG
  2007.     fprintf(fpDebug,"AwayVar: [%s]->[%s]\n",
  2008.         (szAwayVar ? szAwayVar : "<NULL"),
  2009.         (szAway ? szAway : "<NULL>"));
  2010.     #endif
  2011.     
  2012.     return(szAway == NULL);
  2013. }
  2014.  
  2015.  
  2016.  
  2017.  
  2018. /* Returns the number of kilobytes of free storage available on
  2019.    the disk in which szDirectory resides. */
  2020. int FreeSpaceOnDisk(char * szDirectory)
  2021. {
  2022.     BPTR MyLock = Lock(szDirectory, ACCESS_READ);
  2023.     LONG ulBlocksFree;
  2024.     __aligned struct InfoData MyData;
  2025.     
  2026.     if (MyLock == 0)
  2027.     {
  2028.         #ifdef DEBUG_FLAG
  2029.         fprintf(fpDebug,"FreeSpaceOnDisk:  Lock of [%s] failed.\n",szDirectory); fflush(fpDebug);
  2030.         #endif
  2031.         return(0);
  2032.     }
  2033.     
  2034.     Info(MyLock, &MyData);
  2035.         
  2036.     ulBlocksFree = MyData.id_NumBlocks - MyData.id_NumBlocksUsed;
  2037.  
  2038.     UnLock(MyLock);
  2039.     return(ulBlocksFree * MyData.id_BytesPerBlock / 1024);
  2040. }
  2041.  
  2042.  
  2043.  
  2044.  
  2045. /* Returns the amount of disk space we can likely give for the incoming message */
  2046. int SpaceFreeForMessage(char * szDirectory, int nMaxSize)
  2047. {
  2048.     int nSpaceUsedInDir, nSpaceFreeOnDisk, nReturn;
  2049.  
  2050.     /* no saving if the save directory isn't defined! */
  2051.     if (szMessageDir == NULL) 
  2052.     {
  2053.         DEBUG("SpaceFreeForMessage: No VoiceMailDir specified\n");
  2054.         return(0);    
  2055.     }
  2056.  
  2057.     /* no saving if we have an error reading the dir! */
  2058.     if ((nSpaceUsedInDir = SpaceUsedInDir(szDirectory)) < 0) 
  2059.     {
  2060.         DEBUG("SpaceFreeForMessage: SpaceUsedInDir() returned error\n");
  2061.         return(0);
  2062.     }
  2063.         
  2064.     /* initial estimate:  maxsize - sizeof(all files) */
  2065.     nReturn = nMaxSize - nSpaceUsedInDir;
  2066.  
  2067.     /* No space in directory, per user? */    
  2068.     if (nReturn <= 0) 
  2069.     {
  2070.         DEBUG("SpaceFreeForMessage: Directory full.\n");
  2071.         return(0);
  2072.     }
  2073.         
  2074.     /* chop that to the amount of free space on disk */
  2075.     nSpaceFreeOnDisk = FreeSpaceOnDisk(szDirectory);
  2076.     if (nReturn >= nSpaceFreeOnDisk) nReturn = nSpaceFreeOnDisk-1;
  2077.  
  2078.     /* chop that to the maximum message size */
  2079.     if (nReturn > nMaxMessageSize) nReturn = nMaxMessageSize;
  2080.     
  2081.     /* no bloody negative values either */
  2082.     if (nReturn < 0) 
  2083.     {
  2084.         DEBUG("SpaceFreeForMessage: Return was less than zero.\n");
  2085.         nReturn = 0;
  2086.     }
  2087.     
  2088.     return(nReturn);
  2089. }
  2090.  
  2091.  
  2092.  
  2093. /* Returns the sum of the filesizes of each file in a directory. */
  2094. /* returns -1 on error */
  2095. int SpaceUsedInDir(char * szDirectory)
  2096. {
  2097.     BPTR MyLock = Lock(szDirectory, ACCESS_READ);
  2098.     LONG ulBytesUsed = 0;
  2099.     BOOL BMore;
  2100.     struct ExAllControl * eac;
  2101.     struct ExAllData * ead;
  2102.     __aligned UBYTE EAData[sizeof(struct ExAllData)*30];
  2103.     
  2104.     if (MyLock == 0) 
  2105.     {
  2106.         #ifdef DEBUG_FLAG
  2107.         fprintf(fpDebug, "SpaceUsedInDir: Lock of [%s] failed.\n",szDirectory); fflush(fpDebug);
  2108.         #endif
  2109.         return(-1);
  2110.     }
  2111.     
  2112.     eac = AllocDosObject(DOS_EXALLCONTROL,NULL);
  2113.     if (eac == NULL)
  2114.     {
  2115.         #ifdef DEBUG_FLAG
  2116.         fprintf(fpDebug, "SpaceUsedInDir: AllocDosObject failed.\n"); fflush(fpDebug);
  2117.         #endif
  2118.         UnLock(MyLock);
  2119.         return(-1);    
  2120.     }
  2121.     
  2122.     eac->eac_LastKey = 0;    /* very important! */
  2123.     
  2124.     do 
  2125.     {
  2126.         BMore = ExAll(MyLock, (struct ExAllData *) EAData, sizeof(EAData), ED_SIZE, eac);
  2127.         if ((!BMore)&&(IoErr() != ERROR_NO_MORE_ENTRIES)) 
  2128.         {
  2129.             #ifdef DEBUG_FLAG
  2130.             fprintf(fpDebug, "SpaceUsedInDir: ExAll terminated abnormally.\n"); fflush(fpDebug);
  2131.             #endif
  2132.             break;
  2133.         }
  2134.         if (eac->eac_Entries == 0)
  2135.         {
  2136.             /* ExAll has no more entries? */
  2137.             continue;    /* more is *usually* zero */
  2138.         }
  2139.         
  2140.         ead = (struct ExAllData *) EAData;
  2141.         do {
  2142.             ulBytesUsed += ead->ed_Size;
  2143.             ead = ead->ed_Next;
  2144.         } while (ead);
  2145.     } while (BMore);
  2146.     
  2147.     FreeDosObject(DOS_EXALLCONTROL, eac);    
  2148.     UnLock(MyLock);
  2149.     return(ulBytesUsed / 1024);
  2150. }
  2151.  
  2152. /* Presents an EasyRequest() and */
  2153. /* returns one of the OPTION_ defines, depending on what the user chooses */
  2154. static int UserReceiveOption(BOOL BCanTakeMessage, char * szMessage)
  2155. {
  2156.     char szOptions[100] = "\0";
  2157.     char szTitle[100];    
  2158.     int nResults[4];
  2159.     int nNext = 1;
  2160.     
  2161.     /* We can do a two-way IFF we're not a Relay */
  2162.     UNLESS(BImARelay)
  2163.     {
  2164.         strcat(szOptions,"Receive & XMit|");
  2165.         nResults[nNext++] = OPTION_TWOWAY;
  2166.     }
  2167.     
  2168.     /* We can always just receive */
  2169.     strcat(szOptions,"Receive Only|");
  2170.     nResults[nNext++] = OPTION_LISTEN;
  2171.  
  2172.     /* We can take a message if the arg says so */
  2173.     if (BCanTakeMessage)
  2174.     {
  2175.         strcat(szOptions,"Take Message|");
  2176.         nResults[nNext++] = OPTION_TAKEMESSAGE;
  2177.     }
  2178.  
  2179.     /* And we can always deny */
  2180.     strcat(szOptions,"Deny");
  2181.     nResults[0] = OPTION_DENY;
  2182.     
  2183.     sprintf(szTitle,"AmiPhone Connection Request [Key %lu]",ulKeyCode);
  2184.     return(nResults[DMakeReq(szTitle, szMessage, szOptions)]);
  2185. }
  2186.  
  2187.  
  2188.  
  2189. /* a NULL == Do default info */
  2190. #define BLINK(x) (BBlink ? x : ' ')
  2191. void SetWindowTitle(char * szOptTitle)
  2192. {
  2193.     static char szIntWinTitle[100];
  2194.     static BOOL BBlink = FALSE;
  2195.     char cBlinkChar;
  2196.     
  2197.     if (MyInfo.BErrorR) cBlinkChar = 'X';
  2198.     else
  2199.     {
  2200.         switch(nQMode)
  2201.         {
  2202.             case QMODE_EMPTY: cBlinkChar = '+'; break;
  2203.             case QMODE_FLUSH: cBlinkChar = '-'; break;
  2204.         }
  2205.     }
  2206.  
  2207.     if (szOptTitle) Strncpy(szIntWinTitle, szOptTitle, sizeof(szIntWinTitle));
  2208.     else 
  2209.     {
  2210.         char szNum[20];
  2211.  
  2212.         sprintf(szNum,"%i.%is",nQLengthMS/1000,(nQLengthMS%1000)/100);
  2213.         sprintf(szIntWinTitle, "AmiPhoned:[%s] [%s] %c", szShortPeerName, szNum, BLINK(cBlinkChar));
  2214.     }
  2215.  
  2216.     if (AmiPhonedWindow) 
  2217.     {
  2218.         int nCheckWidth = TextLength(&AmiPhonedScreen->RastPort, szIntWinTitle, strlen(szIntWinTitle))+EXTRA_WINDOW_WIDTH;
  2219.         if (nCheckWidth > nWindowWidth)
  2220.         {
  2221.             SizeWindow(AmiPhonedWindow, (nCheckWidth-nWindowWidth)+3, 0);
  2222.             nWindowWidth = nCheckWidth+3;
  2223.         }
  2224.         SetWindowTitles(AmiPhonedWindow, szIntWinTitle, (char *) ~0);
  2225.     }
  2226.     
  2227.     /* Well, 'e won't clear it for us, so we gotta! */
  2228.     if (BNoClient == TRUE) MyInfo.BErrorR = FALSE;
  2229.  
  2230.     BBlink = Not[BBlink];
  2231. }
  2232.  
  2233.  
  2234. /* Returns the number of milliseconds this packet will take to play */
  2235. /* The packet must be already decompressed to get the right result. */
  2236. int PacketTime(struct AmiPhonePacketHeader * ubPacket)
  2237. {
  2238.     return((ubPacket->ulDataLen*1000)/ubPacket->ulBPS);
  2239. }
  2240.  
  2241.  
  2242.  
  2243. /* Main program */
  2244. int main(int argc, char ** argv)
  2245. {
  2246. #ifdef DEBUG_FLAG
  2247.     char szDebugWindowTitle[100];
  2248. #endif
  2249.     char szErrorMessage[80];
  2250.     char * szCurrentUser;
  2251.     struct Process * me;
  2252.     struct DaemonMessage * dm;
  2253.     char cTemp;
  2254.     const char szNoUDPPort[] = "Couldn't set up the UDP socket";
  2255.  
  2256.     atexit(CleanExit);
  2257.  
  2258.     /* make a note of what time it is now */
  2259.     tTimeConnected = time(NULL);
  2260.  
  2261.     if ((szCurrentUser = OpenLibraries(TRUE)) != NULL)
  2262.     {
  2263.         sprintf(szErrorMessage,"Couldn't open %s.library", szCurrentUser);
  2264.         EXIT(szErrorMessage,RETURN_ERROR);
  2265.     }
  2266.  
  2267.       SetErrnoPtr(&errno, sizeof(errno));
  2268.  
  2269. #ifdef DEBUG_FLAG
  2270.     /* Setup debugging output window */
  2271.     sprintf(szDebugWindowTitle,"con:////AmiPhoned_Debug_Window");
  2272.     UNLESS (fpDebug = fopen(szDebugWindowTitle,"w")) EXIT("Couldn't open debugging console",RETURN_ERROR)
  2273. #endif
  2274.  
  2275.     /* Find our inner self */    
  2276.     me = (struct Process *) FindTask(NULL);    
  2277.     
  2278.     /* raise our priority */
  2279.     SetTaskPri((struct Task *)me, nPri);
  2280.  
  2281.     /* Get any relevant info from the AmiPhone icon */
  2282.     ParseArgs();
  2283.  
  2284.     /* no argument for nMaxMessageSize == same as nMaxVoiceMailDirSize */
  2285.     if (nMaxMessageSize < 0) nMaxMessageSize = nMaxVoiceMailDirSize;
  2286.     
  2287.     DEBUG("AmiPhone daemon starting\n")
  2288.  
  2289.     UNLESS (dm = (struct DaemonMessage *)me->pr_ExitData) EXIT("AmiPhoned may only be started by inetd",RETURN_ERROR)
  2290.     UNLESS (AcceptTCPSocket(dm))       EXIT("Accept socket failed", RETURN_OK)
  2291.  
  2292.     GetPhonePeerName(targethost, sizeof(targethost));
  2293.     sprintf(szErrorMessage, "AmiPhone %sconnection requested by\n[%s]",BImARelay?"relay ":"",targethost);
  2294.  
  2295.     UNLESS(SetupTCPQueue(CLIENT_TCP_QUEUE, TRUE)) EXIT("Couldn't setup TCP queue", RETURN_ERROR)
  2296.         
  2297.     #ifdef DEBUG_FLAG
  2298.     fprintf(fpDebug,"connection from [%s] (BNoReq = %i)\n",targethost,BNoReq);
  2299.     fflush(fpDebug);
  2300.     #endif
  2301.  
  2302.     /* Calculate maximum length the message can be */
  2303.     ulSignalMessageFree = SpaceFreeForMessage(szMessageDir, nMaxVoiceMailDirSize);    /* max value set by user for whole dir */
  2304.     ulByteTicker = 1024 * ulSignalMessageFree;     /* and in bytes */
  2305.  
  2306.     #ifdef DEBUG_FLAG
  2307.     fprintf(fpDebug,"There are %i kbytes free for a message\n",ulSignalMessageFree); fflush(fpDebug);
  2308.     #endif
  2309.  
  2310.     if ((BNoReq)||(UserHere() == FALSE))
  2311.     {
  2312.         cTemp = PCREPLY_WILLLISTEN;
  2313.         if (UserHere() == FALSE) 
  2314.         {
  2315.             cTemp = (ulSignalMessageFree > 0) ? PCREPLY_LEAVEMESSAGE : PCREPLY_CANTLEAVEMESSAGE;
  2316.         }
  2317.         UNLESS(CreateUDPConnection(cTemp)) EXIT(szNoUDPPort,RETURN_ERROR)
  2318.     }
  2319.     else
  2320.     {
  2321.          switch (UserReceiveOption((ulSignalMessageFree > 0), szErrorMessage))
  2322.          {    
  2323.              case OPTION_DENY: 
  2324.                  SendCommandPacket(PHONECOMMAND_DENY,0,0L);
  2325.                  EXIT("Connection denied",RETURN_OK)
  2326.                  break;
  2327.                  
  2328.             case OPTION_TWOWAY: 
  2329.                 LaunchXMitter(targethost); 
  2330.                 UNLESS(CreateUDPConnection(PCREPLY_TWOWAY)) EXIT(szNoUDPPort,RETURN_ERROR)
  2331.                 break;
  2332.  
  2333.             case OPTION_LISTEN:    
  2334.                 BOpenWindow = TRUE;
  2335.                 UNLESS(CreateUDPConnection(PCREPLY_WILLLISTEN)) EXIT(szNoUDPPort,RETURN_ERROR)
  2336.                 break;
  2337.                 
  2338.             case OPTION_TAKEMESSAGE:
  2339.                 BOpenWindow |= BImARelay;
  2340.                 UNLESS(CreateUDPConnection(PCREPLY_LEAVEMESSAGE)) EXIT(szNoUDPPort,RETURN_ERROR)
  2341.                 break;
  2342.         }
  2343.     }
  2344.  
  2345.     if (AllocPacketList(TRUE) == FALSE) 
  2346.         EXIT("AllocPacketList failed",RETURN_ERROR);
  2347.                 
  2348.     /* Set up our message for the local AmiPhone */
  2349.     SetUpLocalAmiPhoneInfo(&MyInfo);
  2350.  
  2351.     /* CTRL_C causes exit, CTRL_D causes break of Wait(), and thus re-read of info, CTRL_E causes window open/close */
  2352.     ulPhonedMask = (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E);
  2353.  
  2354.     /* Second, if we haven't already notified the client of our info, tell him now */
  2355.     UNLESS(BLocalAmiPhoneNotified) BLocalAmiPhoneNotified = SendMessageToClient(MSG_CONTROL_HI);
  2356.     
  2357.     /* Open window, if necessary */
  2358.     if (BOpenWindow) OpenTitleBar(&ulPhonedMask);
  2359.         
  2360.     /* Let the client know if his version is out-of-date */
  2361.     if (BSendWarningBack) SendCommandPacket(PHONECOMMAND_VWARN,0,VERSION_NUMBER);
  2362.  
  2363.     /* Spend the rest of our life, waiting... how tragic */
  2364.     while (BDone == FALSE) PhonedWait(ulPhonedMask);
  2365.     EXIT("Client disconnected",RETURN_OK);
  2366. }
  2367.